J'essaie de reprogrammer mon code Stata en Python pour améliorer la vitesse, et j'ai été dirigé dans la direction de PANDAS. Cependant, j'ai du mal à comprendre comment traiter les données.
Disons que je veux parcourir toutes les valeurs dans l'en-tête de colonne 'ID'. Si cet ID correspond à un numéro spécifique, je souhaite modifier les deux valeurs correspondantes FirstName et LastName.
Dans Stata, cela ressemble à ceci:
replace FirstName = "Matt" if ID==103
replace LastName = "Jones" if ID==103
Cela remplace donc toutes les valeurs de FirstName qui correspondent aux valeurs de ID == 103 à Matt.
Dans PANDAS, j'essaie quelque chose comme ça
df = read_csv("test.csv")
for i in df['ID']:
if i ==103:
...
Je ne sais pas où aller d'ici. Des idées?
Une option consiste à utiliser les fonctions de tranchage et d'indexation de Python pour évaluer logiquement les emplacements où votre condition est conservée et y écraser les données.
En supposant que vous puissiez charger vos données directement dans pandas
avec pandas.read_csv
alors le code suivant pourrait vous être utile.
import pandas
df = pandas.read_csv("test.csv")
df.loc[df.ID == 103, 'FirstName'] = "Matt"
df.loc[df.ID == 103, 'LastName'] = "Jones"
Comme mentionné dans les commentaires, vous pouvez également affecter les deux colonnes en une seule fois:
df.loc[df.ID == 103, ['FirstName', 'LastName']] = 'Matt', 'Jones'
Notez que vous aurez besoin de pandas
version 0.11 ou plus récente pour utiliser loc
pour les opérations d’affectation de remplacement.
Une autre façon de le faire est d'utiliser ce que l'on appelle une affectation chaînée. Le comportement de celui-ci est moins stable et il n'est donc pas considéré comme la meilleure solution (c'est explicitement déconseillé dans la documentation), mais il est utile de connaître:
import pandas
df = pandas.read_csv("test.csv")
df['FirstName'][df.ID == 103] = "Matt"
df['LastName'][df.ID == 103] = "Jones"
Vous pouvez utiliser map
, il peut mapper des valeurs à partir d'un dictonairy ou même d'une fonction personnalisée.
Supposons que ceci soit votre df:
ID First_Name Last_Name
0 103 a b
1 104 c d
Créez les dicts:
fnames = {103: "Matt", 104: "Mr"}
lnames = {103: "Jones", 104: "X"}
Et carte:
df['First_Name'] = df['ID'].map(fnames)
df['Last_Name'] = df['ID'].map(lnames)
Le résultat sera:
ID First_Name Last_Name
0 103 Matt Jones
1 104 Mr X
Ou utilisez une fonction personnalisée:
names = {103: ("Matt", "Jones"), 104: ("Mr", "X")}
df['First_Name'] = df['ID'].map(lambda x: names[x][0])
Cette question pourrait encore être visitée assez souvent pour que cela vaille la peine de proposer un addendum à la réponse de M. Kassies. La classe intégrée dict
peut être sous-classée de sorte qu'une valeur par défaut soit renvoyée pour les clés "manquantes". Ce mécanisme fonctionne bien pour les pandas. mais voir ci-dessous.
De cette façon, il est possible d'éviter les erreurs clés.
>>> import pandas as pd
>>> data = { 'ID': [ 101, 201, 301, 401 ] }
>>> df = pd.DataFrame(data)
>>> class SurnameMap(dict):
... def __missing__(self, key):
... return ''
...
>>> surnamemap = SurnameMap()
>>> surnamemap[101] = 'Mohanty'
>>> surnamemap[301] = 'Drake'
>>> df['Surname'] = df['ID'].apply(lambda x: surnamemap[x])
>>> df
ID Surname
0 101 Mohanty
1 201
2 301 Drake
3 401
La même chose peut être faite plus simplement de la manière suivante. L'utilisation de l'argument 'default' pour la méthode get
d'un objet dict évite d'avoir à sous-classer un dict.
>>> import pandas as pd
>>> data = { 'ID': [ 101, 201, 301, 401 ] }
>>> df = pd.DataFrame(data)
>>> surnamemap = {}
>>> surnamemap[101] = 'Mohanty'
>>> surnamemap[301] = 'Drake'
>>> df['Surname'] = df['ID'].apply(lambda x: surnamemap.get(x, ''))
>>> df
ID Surname
0 101 Mohanty
1 201
2 301 Drake
3 401
La question initiale concerne un cas d'utilisation spécifique étroit. Pour ceux qui ont besoin de réponses plus génériques, voici quelques exemples:
Étant donné le cadre de données ci-dessous:
import pandas as pd
import numpy as np
df = pd.DataFrame([['dog', 'hound', 5],
['cat', 'ragdoll', 1]],
columns=['animal', 'type', 'age'])
In[1]:
Out[1]:
animal type age
----------------------
0 dog hound 5
1 cat ragdoll 1
Ci-dessous, nous ajoutons une nouvelle colonne description
en tant que concaténation d'autres colonnes à l'aide de l'opération +
Qui est remplacée pour la série. Le formatage de chaîne de fantaisie, les chaînes de caractères f, etc. ne fonctionneront pas ici car le +
S'applique aux scalaires et non aux valeurs 'primitives':
df['description'] = 'A ' + df.age.astype(str) + ' years old ' \
+ df.type + ' ' + df.animal
In [2]: df
Out[2]:
animal type age description
-------------------------------------------------
0 dog hound 5 A 5 years old hound dog
1 cat ragdoll 1 A 1 years old ragdoll cat
Nous obtenons 1 years
Pour le chat (au lieu de 1 year
) Que nous allons corriger ci-dessous à l'aide de conditions.
Ici, nous remplaçons la colonne animal
d'origine par des valeurs provenant d'autres colonnes et utilisons np.where
pour définir une sous-chaîne conditionnelle basée sur la valeur de age
:
# append 's' to 'age' if it's greater than 1
df.animal = df.animal + ", " + df.type + ", " + \
df.age.astype(str) + " year" + np.where(df.age > 1, 's', '')
In [3]: df
Out[3]:
animal type age
-------------------------------------
0 dog, hound, 5 years hound 5
1 cat, ragdoll, 1 year ragdoll 1
Une approche plus souple consiste à appeler .apply()
sur un cadre de données entier plutôt que sur une seule colonne:
def transform_row(r):
r.animal = 'wild ' + r.type
r.type = r.animal + ' creature'
r.age = "{} year{}".format(r.age, r.age > 1 and 's' or '')
return r
df.apply(transform_row, axis=1)
In[4]:
Out[4]:
animal type age
----------------------------------------
0 wild hound dog creature 5 years
1 wild ragdoll cat creature 1 year
Dans le code ci-dessus, la fonction transform_row(r)
prend un objet Series
représentant une ligne donnée (indiqué par axis=1
, La valeur par défaut de axis=0
Fournira un objet Series
pour chaque colonne). Cela simplifie le traitement car nous pouvons accéder aux valeurs "primitives" réelles de la ligne en utilisant les noms de colonne et avoir une visibilité sur les autres cellules de la ligne/colonne donnée.