El objetivo principal es evitar la indexación encadenada y eliminar el SettingWithCopyWarning
.
Aquí la indexación encadenada es algo así como dfc['A'][0] = 111
El documento dice que se debe evitar la indexación encadenada al devolver una vista versus una copia . Aquí hay un ejemplo ligeramente modificado de ese documento:
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
Aquí aColumn
hay una vista y no una copia del DataFrame original, por lo que modificarlo también modificará aColumn
el original dfc
. A continuación, si indexamos la fila primero:
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
Esta vez zero_row
es una copia, por lo que el original dfc
no se modifica.
De estos dos ejemplos anteriores, vemos que es ambiguo si desea o no cambiar el DataFrame original. Esto es especialmente peligroso si escribe algo como lo siguiente:
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
Esta vez no funcionó en absoluto. Aquí queríamos cambiar dfc
, pero en realidad modificamos un valor intermedio dfc.loc[0]
que es una copia y se descarta de inmediato. Es muy difícil predecir si el valor intermedio le gusta dfc.loc[0]
o dfc['A']
es una vista o una copia, por lo que no se garantiza si se actualizará DataFrame original o no. Es por eso que se debe evitar la indexación encadenada, y los pandas generan la SettingWithCopyWarning
actualización para este tipo de indexación encadenada.
Ahora es el uso de .copy()
. Para eliminar la advertencia, haga una copia para expresar su intención explícitamente:
In [12]: zero_row_copy = dfc.loc[0].copy()
In [13]: zero_row_copy['A'] = 444 # This time no warning
Como está modificando una copia, sabe que el original dfc
nunca cambiará y no espera que cambie. Su expectativa coincide con el comportamiento, luego SettingWithCopyWarning
desaparece.
Tenga en cuenta que si desea modificar el DataFrame original, el documento sugiere que utilice loc
:
In [14]: dfc.loc[0,'A'] = 555
In [15]: dfc
Out[15]:
A B
0 555 1
1 bbb 2
2 ccc 3