6.5 GB 文件上的 Pandas read_csv 消耗超过 170 GB RAM

Posted

技术标签:

【中文标题】6.5 GB 文件上的 Pandas read_csv 消耗超过 170 GB RAM【英文标题】:Pandas read_csv on 6.5 GB file consumes more than 170GB RAM 【发布时间】:2015-03-28 23:38:28 【问题描述】:

我想提出这个,只是因为这太疯狂了。也许韦斯有一些想法。该文件非常规则:1100 行 x ~3M 列,数据以制表符分隔,仅由整数 0、1 和 2 组成。显然这不是预期的。

如果我如下预填充一个数据帧,它会消耗大约 26GB 的 RAM。

h = open("ms.txt")
header = h.readline().split("\t")
h.close()
rows=1100
df = pd.DataFrame(columns=header, index=range(rows), dtype=int)

系统信息:

python 2.7.9 ipython 2.3.1 numpy 1.9.1 熊猫 0.15.2.

欢迎任何想法。

【问题讨论】:

这是什么 Python 版本? 如果您转置数据,它的行为会有所不同吗? 10^3 行和 10^6 似乎……倒退了。 我很好奇ms.txt的内容是什么。你在上面调用readline(),这意味着它是一个多行文本文件,然后你split它。您可以发布前 10 行来确定吗? 挖掘read_csv 下的内容,在一般情况下,它看起来像pandas.io.parsers.PythonParser.read 触底,它似乎在日期转换期间复制,在_convert_data 中调用_convert_to_ndarrays它调用_convert_types,然后进一步调用maybe_convert_numeric等一些函数。沿着这条代码轨迹的任何地方,你都可能因为object类型和低效的复制而崩溃。 从另一边来看:通过手动创建一个 1100x3M 的 dtype int8 的 DataFrame,构造后的总内存使用量应该像预期的那样约为 ~3.1G。过去,pandas 的某些角落不能很好地处理多列少行的限制,所以这也可能起到了作用。 【参考方案1】:

你的例子有问题。

在小规模尝试您的代码时,我注意到即使您设置了dtype=int,您实际上最终会在结果数据框中使用dtype=object

header = ['a','b','c']
rows = 11
df = pd.DataFrame(columns=header, index=range(rows), dtype=int)

df.dtypes
a    object
b    object
c    object
dtype: object

这是因为即使您向 pd.read_csv 函数提供了列为 dtype=int 的指令,它也无法覆盖最终由列中的数据确定的 dtypes。

这是因为 pandas 对于 numpy 和 numpy dtypes 是 tightly coupled

问题是,您创建的数据框中没有数据,因此 numpy 默认数据为np.NaN,这不适合整数。

这意味着 numpy 会感到困惑,并默认返回为 object 的 dtype。

对象数据类型的问题。

将 dtype 设置为 object 意味着与将 dtype 设置为整数或浮点数相比,内存消耗和分配时间的开销很大。

您的示例的解决方法。

df = pd.DataFrame(columns=header, index=range(rows), dtype=float)

这很好用,因为np.NaN 可以生活在浮动中。这会产生

a    float64
b    float64
c    float64
dtype: object

而且应该占用更少的内存。

更多关于如何与 dtypes 相关的信息

有关 dtype 的详细信息,请参阅此相关帖子: Pandas read_csv low_memory and dtype options

【讨论】:

【参考方案2】:

我今天遇到了 3 GB 数据的类似问题,我只是对我的编码风格做了一点改变,比如我在代码下面使用的 file.read() 和 file.readline() 方法,下面的代码只加载 1在内存中一次一行

import re

df_list = []

with open("ms.txt", 'r') as f:
    for line in f:
        #process(line)
        line = line.strip()
        columns = re.split("\t", line, maxsplit=4) # you should modify these according to your split criteria
        df_list.append(columns)

这里是将您的数据转换为 pandas 数据框的代码。

import pandas as pd
df = pd.DataFrame(df_list)# here you will have to modify according to your data frame needs

【讨论】:

以上是关于6.5 GB 文件上的 Pandas read_csv 消耗超过 170 GB RAM的主要内容,如果未能解决你的问题,请参考以下文章

Pandas DataFrame 在 Jupyter Notebook 中无法正确显示

Pandas - 导入大小为 4GB 的 CSV 文件时出现内存错误

无法在 Python 中使用 Pandas 或 Blaze 加载大文件(~2gb)

如何使用带有 gzip 压缩选项的 pandas read_csv 读取 tar.gz 文件?

使用 Pandas 或其他方法比较大型 (~40GB) 文本数据

如何将带有文本信息的 1.3 GB csv 文件读入 Python 的 pandas 对象?