python - 如果为空,则 append 到 DataFrame 时出现问题

标签 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

但是,这不起作用。如果我以这种方式 append 到df,则它始终为空。

我在这里找到了问题的答案:appending-to-an-empty-data-frame-in-pandas ...如果空 DataFrame 对象在该方法的范围内,则此方法有效,但不适用于我的情况。根据 @DSM 的评论“但 append 不会就地发生,因此如果需要,您必须存储输出:”

IOW,我需要这样的东西:

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

在我的本地方法中,但这并不能帮助我访问外部作用域变量 df 并 append 到它。

有没有办法让这一切发生?这与用于扩展列表对象内容的 python extend 方法配合得很好(我意识到 DataFrame 不是列表,但是......)。是否有类似的方法可以使用 DataFrame 对象执行此操作,而无需处理 df 的范围问题?

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

最佳答案

在Python3中,您可以使用nonlocal关键字:

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) 份副本——这对性能非常不利。


如果您不需要在 recursive_method 中使用 df 来实现除 append ,最好 append 到列表,然后构造 recursive_method 完成后,DataFrame(通过调用 pd.concat 一次):

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中,如果你必须在recursive_method中使用df,那么你可以通过 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 不能 不应该 append 到就地:

DataFrame 中的基础数据存储在 NumPy 数组中。数据在一个 NumPy 数组来自连续的内存块。有时没有 有足够的空间将 NumPy 数组的大小调整为更大的连续内存块 即使内存可用——想象一下数组夹在中间 其他数据结构。在这种情况下,为了调整数组的大小,需要一个新的更大的数组 内存块必须分配到其他地方,并且来自该内存块的所有数据 必须将原始数组复制到新 block 。一般情况下是做不到的 就地。

DataFrames 确实有一个私有(private)方法 _update_inplace,它可以是 用于将 DataFrame 的基础数据重定向到新数据。这只是一个 伪就地操作,因为新数据(想想 NumPy 数组)必须是 首先分配(以及所有随之而来的复制)。所以使用_update_inplace对它的两次打击:它使用了一种私有(private)方法,(理论上)可能不是 在 Pandas 的 future 版本中,它会带来 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

关于python - 如果为空,则 append 到 DataFrame 时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35493517/

相关文章:

python - 如何在同一文件中编写脚本/库?

JavaScript:全局范围

javascript - javascript中对象的范围和它的上下文有什么区别?

python - Python 中有模块级变量吗?

python - 在 Pandas 上绘制整行

python - 避免检查记录器是否存在

用于访问实例变量的 Python 方法装饰器

python - 妖艳 : give error line in yaml file

python - 将一个非常大的 Pandas 数据框有效地分成较小的数据框,知道大的是有序的

python - 将 2 列合并为 1 列