L'objectif principal est d'éviter l'indexation chaînée et d'éliminer les fichiers SettingWithCopyWarning
.
Ici, l'indexation chaînée est quelque chose comme dfc['A'][0] = 111
Le document a déclaré que l'indexation chaînée devrait être évitée dans Renvoyer une vue par rapport à une copie . Voici un exemple légèrement modifié de ce document:
In [1]: import pandas as pd
In [2]: dfc = pd.DataFrame({'A':['aaa','bbb','ccc'],'B':[1,2,3]})
In [3]: dfc
Out[3]:
A B
0 aaa 1
1 bbb 2
2 ccc 3
In [4]: aColumn = dfc['A']
In [5]: aColumn[0] = 111
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
In [6]: dfc
Out[6]:
A B
0 111 1
1 bbb 2
2 ccc 3
Ici, il aColumn
s'agit d'une vue et non d'une copie du DataFrame d'origine, donc la modification aColumn
entraînera également la modification de l'original dfc
. Ensuite, si nous indexons la ligne en premier:
In [7]: zero_row = dfc.loc[0]
In [8]: zero_row['A'] = 222
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
In [9]: dfc
Out[9]:
A B
0 111 1
1 bbb 2
2 ccc 3
Cette fois zero_row
est une copie, donc l'original dfc
n'est pas modifié.
À partir de ces deux exemples ci-dessus, nous voyons qu'il est ambigu que vous souhaitiez ou non modifier le DataFrame d'origine. Ceci est particulièrement dangereux si vous écrivez quelque chose comme ce qui suit:
In [10]: dfc.loc[0]['A'] = 333
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
In [11]: dfc
Out[11]:
A B
0 111 1
1 bbb 2
2 ccc 3
Cette fois, ça n'a pas marché du tout. Ici, nous voulions changer dfc
, mais nous avons en fait modifié une valeur intermédiaire dfc.loc[0]
qui est une copie et est immédiatement supprimée. Il est très difficile de prédire si la valeur intermédiaire aime dfc.loc[0]
ou dfc['A']
est une vue ou une copie, il n'est donc pas garanti si le DataFrame d'origine sera mis à jour ou non. C'est pourquoi l'indexation chaînée doit être évitée, et pandas génère le SettingWithCopyWarning
pour ce type de mise à jour d'indexation chaînée.
C'est maintenant l'utilisation de .copy()
. Pour éliminer l'avertissement, faites une copie pour exprimer explicitement votre intention:
In [12]: zero_row_copy = dfc.loc[0].copy()
In [13]: zero_row_copy['A'] = 444 # This time no warning
Puisque vous modifiez une copie, vous savez que l'original dfc
ne changera jamais et vous ne vous attendez pas à ce qu'il change. Votre attente correspond au comportement, puis SettingWithCopyWarning
disparaît.
Remarque: si vous souhaitez modifier le DataFrame d'origine, le document vous suggère d'utiliser loc
:
In [14]: dfc.loc[0,'A'] = 555
In [15]: dfc
Out[15]:
A B
0 555 1
1 bbb 2
2 ccc 3