将DataFrame slice作为参数传递给函数而不使用' SettingWithCopyWarning'

时间:2014-11-19 18:36:03

标签: python pandas

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

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

但是,这个辅助函数会引发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的情况下解决这个问题。

另一个复杂因素是,bc的调用有时可能只是简单的b(df),因此切片是可选的。

谢谢。

1 个答案:

答案 0 :(得分:0)

如果你想修改一些东西,最好简单地传递框架和一个面具。

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

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

因此,更好的工作流程是:

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

然后你可以简单地在最后隐藏:

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

然后产生这些链并立即连接。比原位修改效率更高(尽管如果你只是修改了少量的值,那么我的第一种方法可能会更好)。 YMMV。