在pandas DataFrame中设置新列的正确方法是为了避免SettingWithCopyWarning

时间:2017-02-21 23:16:21

标签: python pandas

尝试在netc df中创建一个新列,但我收到了警告

netc["DeltaAMPP"] = netc.LOAD_AM - netc.VPP12_AM

C:\Anaconda\lib\site-packages\ipykernel\__main__.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

在新版本的Pandas中创建字段的正确方法是什么,以避免收到警告?

pd.__version__
Out[45]:
u'0.19.2+0.g825876c.dirty'

4 个答案:

答案 0 :(得分:15)

正如错误中所述,请尝试使用.loc[row_indexer,col_indexer]创建新列。

netc.loc[:,"DeltaAMPP"] = netc.LOAD_AM - netc.VPP12_AM.

备注

通过Pandas Indexing Docs你的代码应该可行。

netc["DeltaAMPP"] = netc.LOAD_AM - netc.VPP12_AM

被翻译为

netc.__setitem__('DeltaAMPP', netc.LOAD_AM - netc.VPP12_AM)

哪个应该具有可预测的行为。 SettingWithCopyWarning仅用于警告用户在链接分配期间出现意外行为(这不是您正在做的事情)。但是,如文档中所述,

  

有时候,如果没有明显的链式索引,会出现SettingWithCopy警告。这些是SettingWithCopy旨在捕获的错误!熊猫可能会试图警告你,你已经这样做了:

然后,文档会继续举例说明即使不期望错误,也可能会出现错误。因此,我无法在没有更多背景的情况下告诉为什么会发生这种情况。

答案 1 :(得分:1)

创建列时,您需要reset_index,特别是如果您已过滤特定值...则不需要使用.loc [row_indexer,col_indexer]

netc.reset_index(drop=True, inplace=True)
netc["DeltaAMPP"] = netc.LOAD_AM - netc.VPP12_AM

然后它应该可以工作了:)

答案 2 :(得分:0)

您的示例不完整,因为它没有显示netc的来源。 netc本身很可能是切片的产物,因此Pandas无法保证它不是视图或副本。

例如,如果您正在执行此操作:

netc = netb[netb["DeltaAMPP"] == 0]
netc["DeltaAMPP"] = netc.LOAD_AM - netc.VPP12_AM

然后,熊猫不会知道netc是视图还是副本。如果是单线的,实际上就是这样:

netb[netb["DeltaAMPP"] == 0]["DeltaAMPP"] = netc.LOAD_AM - netc.VPP12_AM

您可以在其中更清楚地看到双索引。

如果要将netcnetb分开,一种可能的解决方法可能是强制在第一行中进行复制(loc是确保我们不进行复制两次),例如:

netc = netb.loc[netb["DeltaAMPP"] == 0].copy()

另一方面,如果您想用新列修改netb,则可以执行以下操作:

netb.loc[netb["DeltaAMPP"] == 0, "DeltaAMPP"] = netc.LOAD_AM - netc.VPP12_AM

答案 3 :(得分:0)

在将数据分配给通过索引构建的 DataFrame SettingWithCopyWarning 时,我遇到了 df 问题。 两个命令

  • df['new_column'] = something
  • df.loc[:, 'new_column'] = something

没有警告就无法工作。 复制 df (DataFrame.copy()) 后一切正常。

在下面的代码中,比较 df0 = df_test[df_test['a']>3]df1 = df_test[df_test['a']>3].copy()。 对于 df0,两个赋值都会抛出警告。对于 df1,两者都可以正常工作。

>>> df_test
      a     b     c     d  e
0   0.0   1.0   2.0   3.0  0
1   4.0   5.0   6.0   7.0  1
2   8.0   9.0  10.0  11.0  2
3  12.0  13.0  14.0  15.0  3
4  16.0  17.0  18.0  19.0  4
>>> df0 = df_test[df_test['a']>3]
>>> df1 = df_test[df_test['a']>3].copy()
>>> df0['e'] = np.arange(4)
__main__:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
>>> df1['e'] = np.arange(4)
>>> df0.loc[2, 'a'] = 77
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/indexing.py:1719: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  self._setitem_single_column(loc, value, pi)
>>> df1.loc[2, 'a'] = 77
>>> df0
      a     b     c     d  e
1   4.0   5.0   6.0   7.0  0
2  77.0   9.0  10.0  11.0  1
3  12.0  13.0  14.0  15.0  2
4  16.0  17.0  18.0  19.0  3
>>> df1
      a     b     c     d  e
1   4.0   5.0   6.0   7.0  0
2  77.0   9.0  10.0  11.0  1
3  12.0  13.0  14.0  15.0  2
4  16.0  17.0  18.0  19.0  3

顺便说一句:建议阅读有关此问题的文档(警告中的链接)