主要目的是避免链式索引并消除SettingWithCopyWarning。
这里的链式索引类似于dfc['A'][0] = 111
文档说在Returning a view versus a copy 中应该避免使用链式索引。以下是该文档中稍作修改的示例:
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
这里aColumn 是一个视图,而不是原始DataFrame 的副本,因此修改aColumn 将导致原始dfc 也被修改。接下来,如果我们先索引该行:
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
这次zero_row是一个副本,所以原来的dfc没有修改。
从上面这两个例子中,我们看到是否要更改原始 DataFrame 是模棱两可的。如果您编写如下内容,这尤其危险:
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
这一次完全没用。这里我们想更改dfc,但我们实际上修改了一个中间值dfc.loc[0],它是一个副本,并被立即丢弃。很难预测像dfc.loc[0]或dfc['A']这样的中间值是视图还是副本,因此无法保证原始DataFrame是否会更新。这就是为什么应该避免链式索引,pandas 会为这种链式索引更新生成SettingWithCopyWarning。
现在使用.copy()。要消除警告,请制作副本以明确表达您的意图:
In [12]: zero_row_copy = dfc.loc[0].copy()
In [13]: zero_row_copy['A'] = 444 # This time no warning
由于您正在修改副本,因此您知道原始的 dfc 永远不会改变,您也不会期望它会改变。您的期望与行为匹配,然后SettingWithCopyWarning 消失。
注意,如果您确实要修改原始DataFrame,文档建议您使用loc:
In [14]: dfc.loc[0,'A'] = 555
In [15]: dfc
Out[15]:
A B
0 555 1
1 bbb 2
2 ccc 3