Affectation de colonne super simple
Une trame de données pandas est implémentée en tant que dictée ordonnée de colonnes.
Cela signifie que le __getitem__
[]
peut non seulement être utilisé pour obtenir une certaine colonne, mais __setitem__
[] =
peut également être utilisé pour affecter une nouvelle colonne.
Par exemple, cette trame de données peut avoir une colonne ajoutée en utilisant simplement l' []
accesseur
size name color
0 big rose red
1 small violet blue
2 small tulip red
3 small harebell blue
df['protected'] = ['no', 'no', 'no', 'yes']
size name color protected
0 big rose red no
1 small violet blue no
2 small tulip red no
3 small harebell blue yes
Notez que cela fonctionne même si l'index de la trame de données est désactivé.
df.index = [3,2,1,0]
df['protected'] = ['no', 'no', 'no', 'yes']
size name color protected
3 big rose red no
2 small violet blue no
1 small tulip red no
0 small harebell blue yes
[] = est le chemin à parcourir, mais attention!
Cependant, si vous en avez un pd.Series
et essayez de l'attribuer à une trame de données où les index sont désactivés, vous rencontrerez des problèmes. Voir l'exemple:
df['protected'] = pd.Series(['no', 'no', 'no', 'yes'])
size name color protected
3 big rose red yes
2 small violet blue no
1 small tulip red no
0 small harebell blue no
En effet, un pd.Series
par défaut a un index énuméré de 0 à n. Et la [] =
méthode des pandas essaie d'être "intelligente"
Qu'est-ce qui se passe réellement.
Lorsque vous utilisez la [] =
méthode pandas effectue discrètement une jointure externe ou une fusion externe à l'aide de l'index de la trame de données de gauche et de l'index de la série de droite.df['column'] = series
Note de côté
Cela provoque rapidement une dissonance cognitive, car la []=
méthode essaie de faire beaucoup de choses différentes en fonction de l'entrée, et le résultat ne peut être prédit que si vous savez simplement comment les pandas fonctionnent. Je déconseille donc les []=
bases de code, mais lors de l'exploration de données dans un ordinateur portable, c'est très bien.
Contourner le problème
Si tu as un pd.Series
et que vous voulez l'attribuer de haut en bas, ou si vous codez du code productif et que vous n'êtes pas sûr de l'ordre des index, cela vaut la peine de le protéger pour ce type de problème.
Vous pouvez abaisser le pd.Series
à un np.ndarray
ou un list
, cela fera l'affaire.
df['protected'] = pd.Series(['no', 'no', 'no', 'yes']).values
ou
df['protected'] = list(pd.Series(['no', 'no', 'no', 'yes']))
Mais ce n'est pas très explicite.
Un codeur peut venir et dire "Hé, ça a l'air redondant, je vais juste l'optimiser".
Manière explicite
Définir l'index de la pd.Series
pour être l'index de la df
est explicite.
df['protected'] = pd.Series(['no', 'no', 'no', 'yes'], index=df.index)
Ou plus réaliste, vous en avez probablement pd.Series
déjà un disponible.
protected_series = pd.Series(['no', 'no', 'no', 'yes'])
protected_series.index = df.index
3 no
2 no
1 no
0 yes
Peut maintenant être attribué
df['protected'] = protected_series
size name color protected
3 big rose red no
2 small violet blue no
1 small tulip red no
0 small harebell blue yes
Moyen alternatif avec df.reset_index()
Puisque la dissonance d'index est le problème, si vous sentez que l'indice de la trame de données ne doit pas dicter les choses, vous pouvez simplement supprimer l'index, cela devrait être plus rapide, mais ce n'est pas très propre, car votre fonction fait maintenant probablement deux choses.
df.reset_index(drop=True)
protected_series.reset_index(drop=True)
df['protected'] = protected_series
size name color protected
0 big rose red no
1 small violet blue no
2 small tulip red no
3 small harebell blue yes
Remarque sur df.assign
Bien df.assign
que ce soit plus explicite ce que vous faites, il a en fait tous les mêmes problèmes que ci-dessus[]=
df.assign(protected=pd.Series(['no', 'no', 'no', 'yes']))
size name color protected
3 big rose red yes
2 small violet blue no
1 small tulip red no
0 small harebell blue no
Attention juste à ce df.assign
que votre colonne ne soit pas appelée self
. Cela entraînera des erreurs. Cela rend df.assign
malodorant , car il existe ce type d'artefacts dans la fonction.
df.assign(self=pd.Series(['no', 'no', 'no', 'yes'])
TypeError: assign() got multiple values for keyword argument 'self'
Vous pouvez dire: «Eh bien, je n'utiliserai tout simplement pas self
alors». Mais qui sait comment cette fonction évoluera à l'avenir pour prendre en charge de nouveaux arguments. Peut-être que le nom de votre colonne sera un argument dans une nouvelle mise à jour de pandas, provoquant des problèmes de mise à niveau.