Pandas 即使在使用 .loc 后仍然出现 SettingWithCopyWarning
Pandas still getting SettingWithCopyWarning even after using .loc
起初,我尝试编写一些如下所示的代码:
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 后,我尝试了 using.loc:
complete.loc[:, 'AgeGt15'] = complete['Age'] > 15
complete.loc[:, 'WithFamily'] = complete['SibSp'] + complete['Parch'] > 0
但是,我仍然收到相同的警告。给出了什么?
注意:从 pandas 版本 0.24 开始,is_copy
已弃用,将在未来的版本中删除。虽然私有属性 _is_copy
存在,但下划线表示此属性不是 public API 的一部分,因此不应依赖。因此,展望未来,让 SettingWithCopyWarning
保持沉默的唯一正确方法似乎是在全球范围内这样做:
pd.options.mode.chained_assignment = None
当complete = train.dropna()
执行时,dropna
可能return一个副本,所以
出于谨慎考虑,Pandas 将 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
没有影响的副本。对于初学者来说,这可能是一个有用的警告。在您的情况下,您似乎无意通过修改 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
已经是副本,则完全没有意义(除了为了让 警告 静音)。
我通过创建数据帧的副本来解决它:
complete = train.copy()
我认为您的 .loc
解决方案可以工作,如果它不是针对原始数据框中的 np.nan
的话。您可以 complete = train.dropna().reset_index()
或 Pandas .assign() 将避免 SettingWithCopyWarning
并且是创建新列的推荐方式,返回新的数据框对象。你的例子:
complete = complete.assign(**{'AgeGt15': np.where(complete['Age'] > 15, True, False)})
起初,我尝试编写一些如下所示的代码:
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 后,我尝试了 using.loc:
complete.loc[:, 'AgeGt15'] = complete['Age'] > 15
complete.loc[:, 'WithFamily'] = complete['SibSp'] + complete['Parch'] > 0
但是,我仍然收到相同的警告。给出了什么?
注意:从 pandas 版本 0.24 开始,is_copy
已弃用,将在未来的版本中删除。虽然私有属性 _is_copy
存在,但下划线表示此属性不是 public API 的一部分,因此不应依赖。因此,展望未来,让 SettingWithCopyWarning
保持沉默的唯一正确方法似乎是在全球范围内这样做:
pd.options.mode.chained_assignment = None
当complete = train.dropna()
执行时,dropna
可能return一个副本,所以
出于谨慎考虑,Pandas 将 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
没有影响的副本。对于初学者来说,这可能是一个有用的警告。在您的情况下,您似乎无意通过修改 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
已经是副本,则完全没有意义(除了为了让 警告 静音)。
我通过创建数据帧的副本来解决它:
complete = train.copy()
我认为您的 .loc
解决方案可以工作,如果它不是针对原始数据框中的 np.nan
的话。您可以 complete = train.dropna().reset_index()
或 Pandas .assign() 将避免 SettingWithCopyWarning
并且是创建新列的推荐方式,返回新的数据框对象。你的例子:
complete = complete.assign(**{'AgeGt15': np.where(complete['Age'] > 15, True, False)})