tutorial drop columns column python pandas chained-assignment

python - drop - ¿Por qué debería hacer una copia de un marco de datos en pandas?



pandas plot (5)

El objetivo principal es evitar la indexación encadenada y eliminar la 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 es una vista y no una copia del DataFrame original, por lo que modificar aColumn también modificará el aColumn original. 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 dfc original 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 como dfc.loc[0] o dfc[''A''] es una vista o una copia, por lo que no se garantiza si DataFrame original se actualizará o no. Es por eso que se debe evitar la indexación encadenada, y los pandas generan el SettingWithCopyWarning para este tipo de actualización 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 dfc original nunca cambiará y no espera que cambie. Su expectativa coincide con el comportamiento, luego desaparece SettingWithCopyWarning .

Tenga en cuenta que si desea modificar el DataFrame original, el documento sugiere que use loc :

In [14]: dfc.loc[0,''A''] = 555 In [15]: dfc Out[15]: A B 0 555 1 1 bbb 2 2 ccc 3

Al seleccionar un subtrama de datos de un marco de datos primario, noté que algunos programadores hacen una copia del marco de datos utilizando el método .copy() .

¿Por qué están haciendo una copia del marco de datos? ¿Qué pasará si no hago una copia?


En general, es más seguro trabajar en copias que en marcos de datos originales, excepto cuando sabe que ya no necesitará el original y desea continuar con la versión manipulada. Normalmente, aún tendría algún uso para que el marco de datos original se compare con la versión manipulada, etc. Por lo tanto, la mayoría de las personas trabajan en copias y se fusionan al final.


Es necesario mencionar que devolver la copia o la vista depende del tipo de indexación.

La documentación de los pandas dice:

Devolver una vista versus una copia

Las reglas sobre cuándo se devuelve una vista de los datos dependen completamente de NumPy. Siempre que una matriz de etiquetas o un vector booleano estén involucrados en la operación de indexación, el resultado será una copia. Con una sola etiqueta / indexación y corte escalar, por ejemplo, df.ix [3: 6] o df.ix [:, ''A''], se devolverá una vista.


Esto amplía la respuesta de Pablo. En Pandas, la indexación de un DataFrame devuelve una referencia al DataFrame inicial. Por lo tanto, cambiar el subconjunto cambiará el DataFrame inicial. Por lo tanto, querrá usar la copia si desea asegurarse de que el DataFrame inicial no cambie. Considere el siguiente código:

df = DataFrame({''x'': [1,2]}) df_sub = df[0:1] df_sub.x = -1 print(df)

Obtendrás:

x 0 -1 1 2

En contraste, lo siguiente deja df sin cambios:

df_sub_copy = df[0:1].copy() df_sub_copy.x = -1


Porque si no hace una copia, los índices aún pueden manipularse en otro lugar, incluso si asigna el dataFrame a un nombre diferente.

Por ejemplo:

df2 = df func1(df2) func2(df)

func1 puede modificar df modificando df2, para evitar eso:

df2 = df.copy() func1(df2) func2(df)