即使在使用.loc之后,Pandas仍然会获得SettingWithCopyWarning

时间:2016-08-07 00:18:41

标签: python pandas chained-assignment

首先,我尝试编写一些看起来像这样的代码:

import numpy as np
import pandas as pd
np.random.seed(2016)
train = pd.DataFrame(np.random.choice([np.nan, 1, 2], size=(10, 3)), 
                     columns=['Age', 'SibSp', 'Parch'])

complete = train.dropna()    
complete['AgeGt15'] = complete['Age'] > 15

获得SettingWithCopyWarning后,我尝试使用.loc:

complete.loc[:, 'AgeGt15'] = complete['Age'] > 15
complete.loc[:, 'WithFamily'] = complete['SibSp'] + complete['Parch'] > 0

但是,我仍然得到同样的警告。是什么给了什么?

3 个答案:

答案 0 :(得分:16)

注意:从pandas版本0.24起,is_copy已弃用,将在以后的版本中删除。虽然私有属性_is_copy存在,但下划线表明此属性不是公共API的一部分,因此不应依赖它。因此,展望未来,似乎唯一正确的方法是SettingWithCopyWarning,这将是全球性的:

pd.options.mode.chained_assignment = None

执行complete = train.dropna()时,dropna可能会返回副本,因此 出于谨慎的考虑,熊猫将complete.is_copy设置为Truthy 值:

In [220]: complete.is_copy
Out[220]: <weakref at 0x7f7f0b295b38; to 'DataFrame' at 0x7f7eee6fe668>

这允许Pandas稍后警告您,当执行complete['AgeGt15'] = complete['Age'] > 15时您可能正在修改对train无效的副本。对于初学者来说,这可能是一个有用的警告。在您的情况下,您似乎无意通过修改train间接修改complete。因此,警告只是你的无意义的烦恼。

您可以通过设置

来使警告静音
complete.is_copy = False

这比制作实际副本要快,并将SettingWithCopyWarning压在萌芽状态(点where _check_setitem_copy is called):

def _check_setitem_copy(self, stacklevel=4, t='setting', force=False):
    if force or self.is_copy:
        ...

如果您确信自己知道自己在做什么,可以通过

全局关闭SettingWithCopyWarning
pd.options.mode.chained_assignment = None # None|'warn'|'raise'

答案 1 :(得分:1)

我通过创建数据框副本来解决该问题:

complete = train.copy()

答案 2 :(得分:0)

我认为,如果不是原始数据帧中的.loc,则您的np.nan解决方案会起作用。您可以complete = train.dropna().reset_index()Pandas .assign()避免使用SettingWithCopyWarning,这是创建新列,返回新数据框对象的推荐方法。您的示例:

complete = complete.assign(**{'AgeGt15': np.where(complete['Age'] > 15, True, False)})