将 DataFrame 切片作为参数传递给没有“SettingWithCopyWarning”的函数

Posted

技术标签:

【中文标题】将 DataFrame 切片作为参数传递给没有“SettingWithCopyWarning”的函数【英文标题】:Passing DataFrame slice as argument to function without 'SettingWithCopyWarning' 【发布时间】:2015-01-17 09:59:31 【问题描述】:

我有一个将数据帧作为参数的函数,在处理此数据帧时,它调用另一个函数,将同一数据帧的切片作为参数传递给辅助函数。

所有更改都已就地完成,因此不会返回任何内容(因为数据框的大小)。

但是,这个辅助函数引发了SettingWithCopyWarning,因为它不再处理原始数据帧。

这是一个例子:

import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(9).reshape(3,3), columns=list('abc'))
print df

def a(df):
    if df.is_copy:
        print 'a got a copy'
    df['a'] = 'a'

def b(df):
    if df.is_copy:
        print 'b got a copy'
        print df.is_copy
    df.loc[:,'b'] = 'b'

def c(df):
    a(df)
    b(df.loc[0:1,:])
    if df.is_copy:
        print 'c got a copy'
    df.loc[0:1,'c'] = 'c'

def d(df):
    new_df = df.loc[0:1].copy(deep=True)
    b(new_df)
    df.update(new_df)
    del new_df

c(df)
df

结果:

b got a copy
<weakref at 000000000C1DE778; to 'DataFrame' at 000000000C1B9DA0>

   a  b  c
0  a  1  c
1  a  4  c
2  a  7  8

我知道一种选择是从原始切片创建一个新数据帧并将其传递给b,然后df.update(new_df)d 表明它有效:

d(df)
df

产生所需的输出:

   a  b  c
0  a  b  c
1  a  b  c
2  a  7  8

但是有没有办法在不创建新数据框和提高 SettingWithCopyWarning 的情况下处理这个问题。

另一个复杂情况是,从c 内部调用b 有时可能只是简单的b(df),因此切片是可选的。

谢谢。

【问题讨论】:

【参考方案1】:

如果你想修改东西,最好简单地传递框架和蒙版。

def b(df, row_mask):
    df.loc[row_mask,'b'] = 'foo'

虽然通常我不会修改这样的东西,特别是如果它是一个大框架。当您更改 dtypes 时,这些修改会触发副本(例如,将“b”放在包含所有数字的列中通常不是您应该做的,dtypes 是基于列的)。

所以更好的工作流程是这样做:

def b(df):
    sliced = df.loc[0:1].copy()
    sliced.loc[:,'b'] = 'foo'
    return sliced

那么你就可以简单地在末尾连接:

result = pd.concat([b(df), df[1:]])

然后生成这些链并立即连接所有内容。将比就地修改更有效(尽管如果您只修改少量值,那么我的第一种方法可能会更好)。 YMMV。

【讨论】:

谢谢你,杰夫。这很有帮助。实际上没有打算更改 dtype - 这可能是使用错误的示例。但是,我对您的第二个选项感到有些困惑。 1) 如果df.memory_usage() 显示大约 4 GB(可用的 8 GB),df.loc[0:1].copy() 不会增加整体内存占用吗? 2)如果我必须将掩码传递给您的第二个b(如果切片索引是在b之外定义的)我是否正确理解第二个b需要根据第一个b进行修改(即掩码需要与df一起传递)?再次感谢。 这取决于 j 有一个巨大的框架通常会更好地处理它

以上是关于将 DataFrame 切片作为参数传递给没有“SettingWithCopyWarning”的函数的主要内容,如果未能解决你的问题,请参考以下文章

将过滤器作为参数传递给 Dataframe.filter 函数

如何将编码器作为参数传递给数据帧的 as 方法

将 xml 数据作为存储过程的参数传递给 s-s-rs

将一个表字段作为参数传递给 s-s-rS 报告中的另一个表

将查询作为参数传递给 udf 函数

MVC - 将整个模型作为参数传递给 JavaScript 中的 Url.Action