【问题标题】:Pandas still getting SettingWithCopyWarning even after using .loc即使在使用 .loc 之后,熊猫仍然会得到 SettingWithCopyWarning
【发布时间】:2016-12-13 01:59:27
【问题描述】:

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

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

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

【问题讨论】:

标签: python pandas chained-assignment


【解决方案1】:

注意:从 pandas 0.24 版开始,is_copy 已被弃用,并将在未来的版本中删除。虽然存在私有属性 _is_copy,但下划线表示此属性不是公共 API 的一部分,因此不应依赖。因此,展望未来,让SettingWithCopyWarning 保持沉默的唯一正确方法似乎是在全球范围内这样做:

pd.options.mode.chained_assignment = None

complete = train.dropna() 被执行时,dropna 可能会返回一个副本,所以 出于谨慎考虑,Pandas 将 complete.is_copy 设置为 Truthy 价值:

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

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

您可以通过设置使警告静音,

complete.is_copy = False       # deprecated as of version 0.24

这比制作实际副本更快,并将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'

另一种消除警告的方法是制作一个新副本:

complete = complete.copy()

但是,如果 DataFrame 很大,您可能不想这样做,因为复制 可能会占用大量时间和内存,而且它是 如果您知道complete 已经是一个副本,那么完全没有意义(除了为了消除警告)。

【讨论】:

  • 你觉得这一致吗?它对drop_duplicates 发出相同的警告,但对drop 没有。
  • @ayhan:如果使用complete = complete.assign(AgeGt15=(complete['Age'] &gt; 15)),也不会发出警告。 Pandas 用来推断SettingWithCopyWarning 的机制并非万无一失。它涵盖了最常见的情况,但不是全部。
【解决方案2】:

我通过创建数据框的副本来解决它:

complete = train.copy()

【讨论】:

  • 虽然标记的答案建议使用 is_copy,但这不是最好的处理方式,因为 is_copy 也会抛出错误消息,指出它已被弃用 -- see panda docs。鉴于此,copy() 是确保不抛出警告消息的最佳方法。
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 2018-09-11
    • 2017-02-23
    • 2016-07-03
    • 1970-01-01
    • 1970-01-01
    • 2014-07-04
    • 2021-11-30
    相关资源
    最近更新 更多