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 文件?