正确的方法来在pandas dataframe中设置新列,以避免设置withCopyWarning



尝试在NetC DF中创建一个新列,但我得到了警告

netc["DeltaAMPP"] = netc.LOAD_AM - netc.VPP12_AM
C:Anacondalibsite-packagesipykernel__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

什么是在较新版本的熊猫中创建字段以避免警告的正确方法?

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

您的示例不完整,因为它没有显示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

正如它在错误中所说的那样,尝试使用 .loc[row_indexer,col_indexer]创建新列。

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

注释

由熊猫索引文档您的代码应起作用。

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

被翻译成

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

应该具有可预测的行为。SettingWithCopyWarning只能在链式分配过程中警告用户意外行为(这不是您在做的事情)。但是,如文档中所述,

有时会在没有明显的链接索引进行时会出现SettingWithCopy警告。这些是SettingWithCopy旨在捕获的错误!Pandas可能试图警告您您已经做到了:

然后,文档继续举例说明即使没有预期,何时可能会出现该错误。所以我无法说出为什么没有更多上下文会发生这种情况。

i具有 SettingWithCopyWarning issue,当将数据分配给数据框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

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

您需要reset_index何时创建列,尤其是当您对特定值进行过滤时...然后您不需要使用.loc [row_indexer,col_indexer]

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

然后它应该有效:)

正如其他答案中指出的那样,您很有可能对数据进行了一些过滤,否则此警告不应弹出(因为您的步骤正确)。/p>

假设您已经进行了一些过滤,则可以尝试执行以下步骤:

netc_copied = netc.copy()
netc.loc[:, "DeltaAMPP"] = netc_copied["LOAD_AM"] - netc_copied["VPP12_AM"]

请注意,我在原始数据框架中添加了一个新列。您也可以在复制的数据框架中执行此操作。

一个更简单的解决方案是仅使用'sigtion':

netc = netc.assign(DeltaAMPP=netc_copied['LOAD_AM']-netc_copied['VPP12_AM'])

另外您也可以使用eval

netc.eval('DeltaAMPP = LOAD_AM - VPP12_AM', inplace = True)

由于inplace=True您无需将其分配给netc

即使使用.loc或.iloc进行切片,您仍然会出现错误,您要做的就是切片后重置索引

df.reset_index()

最新更新