如何在不遇到 MemoryError 的情况下连接多个 pandas.DataFrames

新手上路,请多包涵

我有三个要连接的 DataFrame。

 concat_df = pd.concat([df1, df2, df3])

这会导致 MemoryError。我该如何解决这个问题?

请注意,大多数现有的类似问题都是关于读取大文件时发生的 MemoryErrors。我没有那个问题。我已将我的文件读入 DataFrames 中。我只是无法连接这些数据。

原文由 bluprince13 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 928
2 个回答

我很感谢社区的回答。但是,就我而言,我发现问题实际上是由于我使用的是 32 位 Python。

Windows 32 和 64 位操作系统定义了 内存限制。对于 32 位 进程,它只有 2 GB。所以,即使你的 RAM 超过 2GB,即使你运行的是 64 位操作系统,但你运行的是 32 位进程,那么该进程将仅限于 2GB 的 RAM - 在我的例子中是进程是蟒蛇。

我升级到 64 位 Python,从那以后就没有内存错误了!

其他相关问题是: 64 位窗口上的 Python 32 位内存限制我应该使用 Python 32 位还是 Python 64 位为什么这个 numpy 数组太大而无法加载?

原文由 bluprince13 发布,翻译遵循 CC BY-SA 3.0 许可协议

就像在其他答案中看到的那样,问题是记忆问题。一个解决方案是将数据存储在磁盘上,然后构建一个唯一的数据框。

对于如此庞大的数据,性能是一个问题。

csv 解决方案非常慢,因为在文本模式下会发生转换。自从使用二进制模式以来,HDF5 解决方案更短、更优雅、更快。我提出了二进制模式的第三种方式,使用 pickle ,它似乎更快,但更具技术性并且需要更多空间。第四个,手工。

这里的代码:

 import numpy as np
import pandas as pd
import os
import pickle

# a DataFrame factory:
dfs=[]
for i in range(10):
    dfs.append(pd.DataFrame(np.empty((10**5,4)),columns=range(4)))

# a csv solution
def bycsv(dfs):
    md,hd='w',True
    for df in dfs:
        df.to_csv('df_all.csv',mode=md,header=hd,index=None)
        md,hd='a',False
    #del dfs
    df_all=pd.read_csv('df_all.csv',index_col=None)
    os.remove('df_all.csv')
    return df_all



更好的解决方案:

 def byHDF(dfs):
    store=pd.HDFStore('df_all.h5')
    for df in dfs:
        store.append('df',df,data_columns=list('0123'))
    #del dfs
    df=store.select('df')
    store.close()
    os.remove('df_all.h5')
    return df

def bypickle(dfs):
    c=[]
    with open('df_all.pkl','ab') as f:
        for df in dfs:
            pickle.dump(df,f)
            c.append(len(df))
    #del dfs
    with open('df_all.pkl','rb') as f:
        df_all=pickle.load(f)
        offset=len(df_all)
        df_all=df_all.append(pd.DataFrame(np.empty(sum(c[1:])*4).reshape(-1,4)))

        for size in c[1:]:
            df=pickle.load(f)
            df_all.iloc[offset:offset+size]=df.values
            offset+=size
    os.remove('df_all.pkl')
    return df_all


对于同构数据帧,我们可以做得更好:

 def byhand(dfs):
    mtot=0
    with open('df_all.bin','wb') as f:
        for df in dfs:
            m,n =df.shape
            mtot += m
            f.write(df.values.tobytes())
            typ=df.values.dtype
    #del dfs
    with open('df_all.bin','rb') as f:
        buffer=f.read()
        data=np.frombuffer(buffer,dtype=typ).reshape(mtot,n)
        df_all=pd.DataFrame(data=data,columns=list(range(n)))
    os.remove('df_all.bin')
    return df_all

以及对(小,32 Mb)数据进行一些测试以比较性能。对于 4 Gb,您必须乘以大约 128。

 In [92]: %time w=bycsv(dfs)
Wall time: 8.06 s

In [93]: %time x=byHDF(dfs)
Wall time: 547 ms

In [94]: %time v=bypickle(dfs)
Wall time: 219 ms

In [95]: %time y=byhand(dfs)
Wall time: 109 ms

一张支票:

 In [195]: (x.values==w.values).all()
Out[195]: True

In [196]: (x.values==v.values).all()
Out[196]: True

In [197]: (x.values==y.values).all()
Out[196]: True



当然,所有这些都必须改进和调整以适应您的问题。

例如,df3 可以分成大小为“total_memory_size - df_total_size”的块,以便能够运行 bypickle

如果您愿意的话,如果您提供有关数据结构和大小的更多信息,我可以对其进行编辑。美丽的问题!

原文由 B. M. 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题