如果为空,则附加到DataFrame的问题

时间:2016-02-18 22:14:09

标签: python pandas scope append dataframe

我有一个数据框,我在本地方法的范围之外初始化。我想做如下:

def outer_method():
    ... do outer scope stuff here
    df = pd.DataFrame(columns=['A','B','C','D'])
    def recursive_method(arg):
        ... do local stuff here
        # func returns a data frame to be appended to empty data frame
        results_df = func(args)
        df.append(results_df, ignore_index=True)
        return results
recursive_method(arg)
return df

然而,这不起作用。如果我以这种方式附加df,它始终为空。

我在这里找到了我的问题的答案:appending-to-an-empty-data-frame-in-pandas ...这是有效的,如果空的DataFrame对象在方法的范围内,但不是我的情况。根据@ DSM的评论"但附加信息并非就地发生,因此如果您需要,您必须存储输出:"

IOW,我需要有类似的东西:

df = df.append(results_df, ignore_index=True)

在我的本地方法中,但这并不能帮助我访问我的外部范围变量df以附加到它。

有没有办法让这种情况发生?这适用于python extend方法,用于扩展列表对象的内容(我意识到DataFrames不是列表,但是......)。是否有类似的方法使用DataFrame对象执行此操作而无需处理df的范围问题?

顺便说一下,Pandas concat方法也有效,但我遇到了变量范围的问题。

1 个答案:

答案 0 :(得分:3)

在Python3中,您可以使用非本地关键字

def outer_method():
    ... do outer scope stuff here
    df = pd.DataFrame(columns=['A','B','C','D'])
    def recursive_method(arg):
        nonlocal df
        ... do local stuff here
        # func returns a data frame to be appended to empty data frame
        results_df = func(args)
        df = df.append(results_df, ignore_index=True)
        return results

return df

但请注意,每次调用df.append都会返回一个新的DataFrame,因此需要将所有旧数据复制到新的DataFrame中。如果你在一个循环中这样做N次,你最终会产生1 + 2 + 3 + ... + N = O(N ^ 2)份的顺序 - 非常糟糕的性能。

如果您在df内不需要recursive_method用于任何其他目的 附加,最好附加到列表,然后构造 DataFrame(在pd.concat完成后调用recursive_method 一次):

df = pd.DataFrame(columns=['A','B','C','D'])
data = [df]
def recursive_method(arg, data):
    ... do stuff here
     # func returns a data frame to be appended to empty data frame
     results_df = func(args)
     data.append(df_join_out)
     return results
recursive_method(arg, data)
df = pd.concat(data, ignore_index=True)

如果您需要做的只是收集内部数据,这是最佳解决方案 recursive_method并且可以等待之后构建新的df recursive_method已完成。

在Python2中,如果您必须在df内使用recursive_method,那么您可以通过 df作为recursive_method的参数,并返回df

df = pd.DataFrame(columns=['A','B','C','D'])
def recursive_method(arg, df):
    ... do stuff here
     results, df = recursive_method(arg, df)
     # func returns a data frame to be appended to empty data frame
     results_df = func(args)
     df = df.append(results_df, ignore_index=True)
     return results, df
results, df = recursive_method(arg, df)

但请注意,在进行O(N ^ 2)复制时,您将付出沉重的代价 如上所述。

为什么DataFrames 不能不应附加到就地

DataFrame中的基础数据存储在NumPy数组中。一个数据 NumPy数组来自一个连续的内存块。有时没有 足够的空间可以将NumPy阵列调整为更大的内存块 即使内存可用 - 想象一下阵列夹在中间 其他数据结构。在那种情况下,为了调整阵列的大小,新的更大 必须在其他地方分配内存块,并从中分配所有数据 原始数组必须复制到新块。一般来说,它无法完成 在的地方。

DataFrames确实有一个私有方法,_update_inplace 用于将DataFrame的基础数据重定向到新数据。这只是一个 伪现场操作,因为新数据(想想NumPy数组)必须是 首先分配(带有所有话务员复制)。所以使用_update_inplace两次打击:它使用的私有方法(理论上)可能不是 在未来版本的Pandas中,它会导致O(N ^ 2)复制惩罚。

In [231]: df = pd.DataFrame([[0,1,2]])

In [232]: df
Out[232]: 
   0  1  2
0  0  1  2

In [233]: df._update_inplace(df.append([[3,4,5]]))

In [234]: df
Out[234]: 
   0  1  2
0  0  1  2
0  3  4  5