首页 > 解决方案 > 创建一个新列但创建数据框的副本

问题描述

我想检查上面行的值,看看它与当前行相同。我在这里找到了一个很好的答案:df['match'] = df.col1.eq(df.col1.shift())col1就是您要比较的。

但是,当我尝试它时,我收到了SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.警告。我col1的是一个字符串。我知道您可以禁止显示警告,但我将如何检查上面的同一行并确保我没有创建数据框的副本?即使有警告,我确实得到了我想要的输出,但很好奇是否存在更好的方法。

import pandas as pd
data = {'col1':['a','a','a','b','b','c','c','c','d','d'],
       'week':[1,1,1,1,1,2,2,2,2,2]}
df = pd.DataFrame(data, columns=['col1','week'])
df['check_condition'] = 1
while sum(df.check_condition) != 0:
    for week in df.week:
        wk = df.loc[df.week == week]
        wk['match'] = wk.col1.eq(wk.col1.shift()) # <-- where the warning occurs
        # fix the repetitive value...which I have not done yet
        # for now just exit out of the while loop
        df.loc[df.week == week,'check_condition'] = 0

标签: pythonpandas

解决方案


你不能忽视熊猫SettingWithCopyWarning!它 100% 告诉您,您的代码不会按预期工作(如果有的话)。停止,调查并修复它。(这不是您可以过滤掉的可忽略的事情,就像熊猫 FutureWarning 唠叨弃用一样。)

您的代码存在多个问题:

  • 您正在尝试迭代一个数据帧(但不是用groupby()),取它的切片(在 subdataframewk中,这是一个切片的副本)...
  • 然后分配给(不存在的)新列wk['match']。这很糟糕,你不应该这样做。(您可以初始化df['match'] = np.nan,但尝试分配给副本仍然是错误的wk)...
  • SettingWithCopyWarning当您尝试分配给时被触发wk['match']。它告诉您wk是来自 dataframe 的切片的副本df,而不是df它本身。因此,就像它告诉您的那样:A value is trying to be set on a copy of a slice from a DataFrame.该分配只会在每次wk被您的循环覆盖时被丢弃,因此即使您可以强制它继续工作,wk它也是错误的。这就是为什么SettingWithCopyWarning你不应该首先复制 df 切片的代码味道。
  • 稍后,您还尝试df['check_condition']在遍历 df 时分配给列,这也很糟糕。

解决方案:

df['check_condition'] = df['col1'].eq(df['col1'].shift()).astype(int)

df
  col1  week  check_condition
0    a     1                0
1    a     1                1
2    a     1                1
3    b     1                0
4    b     1                1
5    c     2                0
6    c     2                1
7    c     2                1
8    d     2                0
9    d     2                1

更一般地说,对于更复杂的代码,您希望根据某些分组标准迭代每组数据帧,您可以使用 usegroupby()split-apply-combine代替。

  • 您按 分组wk.col1.eq(wk.col1.shift()),即col1值与​​前一行没有变化的行
  • 并且您想check_condition在这些行上设置为 0
  • 和 1 在 col1值确实从前一行发生变化的行上

但在这种更简单的情况下,您可以跳过groupby()并进行直接分配。


推荐阅读