import pandas as pd
import numpy as np
Header=['ALPHA','CL','CD','Cm','CK','CY']
RawData=pd.DataFrame({'sp1L':[0,0,0],
'sp2L':[-10,-10,-10],
'ALPHA':[-6,-5.75,-5.5],
'CL':[-0.10452846326765346,-0.10018806161207627,-0.09584575252022398],
'CD':[0.0024787521766663585,0.003182780796509667,0.004086771438464067],
'Cm':[36,33.0625,30.25]
})
temp=RawData.loc[0:1,:]
for h in Header:
if (h == temp.columns).any():
continue
else:
temp.loc[:,h]=np.nan
问题描述
以上代码在运行时会在最后一句temp.loc[:,h]=np.nan
处报SettingWithCopyWarning,无论如何修改赋值方式都无法去除。
后来发现这是一个隐性的链式索引(chain indexing)语句。
链式索引问题的官方描述
Outside of simple cases, it’s very hard to predict whether it will return a view or a copy (it depends on the memory layout of the array, about which pandas makes no guarantees)
真正导致警告的原因在上面一句:
temp=RawData.loc[0:1,:]
这是一个浅拷贝语句,实际没有将RawData的一个切片复制到一段新的内存中保存,而是仅仅为原切片创建了一个“别名”temp。因此,后续语句在继续对temp进行引用时:
temp.loc[:,h]
相当于
RawData.loc[0:1,:][:,h]
即链式索引方法。
关于链式索引的风险可参考上面的官方解释。
简单说,就是链式索引方式会使得python解释器使用__getitem__(),这样会导致返回值不确定是指定切片的一个copy还是仅为切片指定了一个别名。
如果不想改原数据时,它返回了一个别名,那所有的修改就会直接改在原数据上;反过来,如果想修改原数据,但它返回的是一个copy,更改就无法生效。
具体返回的是什么跟待处理数据的具体格式、大小和pandas对待处理数据的内存规划有关,这些都是不确定的,所以尽量避免使用链式索引。
解决方法
将temp=RawData.loc[0:1,:]
改为深拷贝方法:
import copy # 代码头部加入引用copy库
temp=copy.deepcopy(RawData.loc[IndexPosition,:])
其余部分不变,运行后SettingWithCopyWarning消失。