【问题标题】:SettingwithCopy when creating new column and when dropping NaN rows [duplicate]创建新列和删除 NaN 行时的 SettingwithCopy [重复]
【发布时间】:2017-08-27 04:12:17
【问题描述】:

我一直在寻找阅读 pandas 文档 here 并尝试使用围绕 herehere 发布的问题的不同代码行,但我似乎无法摆脱带有复制警告的设置。我更愿意学习以“正确”的方式对其进行编码,而不仅仅是ignoring the warnings.

以下代码行位于 for 循环中,我不想多次生成此警告,因为它可能会减慢速度。

我正在尝试创建一个名称为:'E'+vs 的新列,其中 vs 是 for 循环中列表中的字符串

但是对于它们中的每一个,我仍然收到以下警告,即使是最后 3 行:

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

这是我迄今为止尝试过的麻烦行:

#based on research, the first two seem to be the "wrong" way

df_out['E'+vs] = df_out[kvs].rolling(v).mean().copy()
df_out['E'+vs] = df_out[kvs].rolling(v).mean()

df_out.loc[:,'E'+vs] = df_out[kvs].rolling(v).mean().copy()
df_out.loc[:,'E'+vs] = df_out[kvs].rolling(v).mean()
df_out.loc[:,'E'+vs] = df_out.loc[:,kvs].rolling(v).mean()

另一个给出 SettingWithCopyWarning 的是:

df_out.dropna(inplace=True,axis=0)

这个也发出警告(但我认为这个会)

df_out = df_out.dropna(inplace=True,axis=0)

如何正确执行这两项操作?

编辑:这是生成原始 df_out 的代码

df_out= pd.concat([vol.Date[1:-1], ret.Return_Time[:-2], vol.Freq_Time[:-2],
               vol.Freq_Time[:-1].shift(-1), vol.Freq_Time[:].shift(-2)],
               axis=1).dropna().set_index('Date')

【问题讨论】:

    标签: python python-3.x pandas chained-assignment


    【解决方案1】:

    这是一个令人困惑的话题。问题不是您发布的代码。这是您尚未发布的代码。这是生成df_out的代码

    考虑这个例子,并记下产生警告的最后一行。

    df_other = pd.DataFrame(dict(A=[1], B=[2]))
    df_out = df_other[:]
    
    df_out['E'] = 5
    
    //anaconda/envs/3.5/lib/python3.5/site-packages/ipykernel/__main__.py:4: 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: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
    

    现在我们将尝试一个不会产生警告的等效方法

    df_other = pd.DataFrame(dict(A=[1], B=[2]))
    df_out = df_other.loc[:]
    
    df_out['E'] = 5
    

    然后

    print `df_out`
    
       A  B  E
    0  1  2  5
    

    归结为 pandas 在基于大量标准构建数据框时决定将 is_copy 属性附加到数据框。

    注意

    df_other[:].is_copy
    
    <weakref at 0x103323458; to 'DataFrame' at 0x116a684e0>
    

    什么时候

    df_other.loc[:].is_copy
    

    返回None


    那么什么类型的构造会触发复制呢?我仍然不知道所有事情,甚至我知道的事情对我来说都没有意义。

    为什么不触发呢?

    df_other[['A', 'B', 'E']].is_copy
    

    【讨论】:

    • 有趣的答案。绝对不清楚 pandas 到底在做什么。我的用例如下。我有一个原始的 df 被传递到包含这两个操作的函数中。比如说,初始 len(df_out) = 1000。操作之后 len(df_out) =998。然后我做其他事情。但是下次我迭代时,我仍然想要 len(df_out) =1000,即原始数据帧。所以为了解决这个问题,在进入函数之前,我做了 df_out = df[:] 来制作原始数据帧的副本。我现在传递给函数。一切正常,但这个愚蠢的警告很烦人。
    • 我检查了 id(df) 不等于 id(df_out)。通过引用传递的值会发生变化,这有点烦人。所以迭代 1,由于删除的行,len 从 1000 变为 998,然后迭代 2 len 从 998 开始到 996,依此类推,这是错误的,因为它应该再次从 1000 开始。
    • 还没弄明白。我会睡在上面。
    • 就这么简单 df.copy() ....facepalm 哈哈
    【解决方案2】:

    首先,我不确定这是有效还是最好的方法。但是,当我向现有数据框添加新列时遇到了同样的问题,我决定使用 reset_index 方法。

    在这里,我首先从 EMPLOYEES 列中删除 Nan 行,并将这个操纵的数据框分配给新的数据框 df1,然后我将 COMPANY_SIZE 列添加到 df1,如下所示:

    df1 = all_merged_years.dropna(subset=['EMPLOYEES']).reset_index()
    
    column = df1['EMPLOYEES']
    
    Size =[]
    
    df1['COMPANY_SIZE'] = ' '
    
    for number in column:
        if number <=999:
            Size.append('Small')
        elif 999<number<=9999:
            Size.append('Medium')
        elif 9999<number:
            Size.append('Large')
        else:
            Size.append('UNKNOWN')
    
    df1['COMPANY_SIZE'] = Size
    

    这样我就没有收到这样的警告。希望有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多