O objetivo principal é evitar a indexação encadeada e eliminar o SettingWithCopyWarning
.
Aqui a indexação encadeada é algo como dfc['A'][0] = 111
O documento dizia que a indexação encadeada deve ser evitada em Retornando uma exibição versus uma cópia . Aqui está um exemplo ligeiramente modificado desse 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
Aqui aColumn
está uma visualização e não uma cópia do DataFrame original; portanto, a modificação também aColumn
fará com que o original dfc
seja modificado. Em seguida, se indexarmos a linha primeiro:
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
Desta vez zero_row
é uma cópia, portanto o original dfc
não é modificado.
A partir desses dois exemplos acima, vemos que é ambíguo se você deseja ou não alterar o DataFrame original. Isso é especialmente perigoso se você escrever algo como o seguinte:
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
Desta vez, não funcionou. Aqui queríamos mudar dfc
, mas na verdade modificamos um valor intermediário dfc.loc[0]
que é uma cópia e é descartado imediatamente. É muito difícil prever se o valor intermediário como dfc.loc[0]
ou dfc['A']
é uma visão ou uma cópia, por isso não é garantido ou não trama de dados original será atualizado. É por isso que a indexação em cadeia deve ser evitada, e o pandas gera o SettingWithCopyWarning
para esse tipo de atualização de indexação em cadeia.
Agora é o uso de .copy()
. Para eliminar o aviso, faça uma cópia para expressar sua intenção explicitamente:
In [12]: zero_row_copy = dfc.loc[0].copy()
In [13]: zero_row_copy['A'] = 444 # This time no warning
Como você está modificando uma cópia, sabe que o original dfc
nunca será alterado e não espera que seja alterado. Sua expectativa corresponde ao comportamento e depois SettingWithCopyWarning
desaparece.
Nota, se você deseja modificar o DataFrame original, o documento sugere que você 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