【问题标题】:pandas memory error after a certain skiprows parameter某个skirows参数后的熊猫内存错误
【发布时间】:2016-08-20 21:01:12
【问题描述】:

我有一个 ~1.81GB 的 CSV 文件,其中有 ~49m 行。它只有一列包含 38 个字符的字符串。

我在 Digital Ocean VPS(Ubuntu 12.04.4、Python 2.7、pandas 0.18.0、512MB RAM)上使用read_csv 阅读此文件。我一次读了5000行。但是,它开始在skiprows = 2800000 引发错误。这是我在重启的计算机上测试的代码,新启动的 Python:

>>> pd.read_csv(filename, skiprows=2800000, nrows=5000, header=None)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ayhan/.conda/envs/swrm/lib/python2.7/site-packages/pandas/io/parsers.py", line 529, in parser_f
    return _read(filepath_or_buffer, kwds)
  File "/home/ayhan/.conda/envs/swrm/lib/python2.7/site-packages/pandas/io/parsers.py", line 295, in _read
    parser = TextFileReader(filepath_or_buffer, **kwds)
  File "/home/ayhan/.conda/envs/swrm/lib/python2.7/site-packages/pandas/io/parsers.py", line 608, in __init__
    self.options, self.engine = self._clean_options(options, engine)
  File "/home/ayhan/.conda/envs/swrm/lib/python2.7/site-packages/pandas/io/parsers.py", line 731, in _clean_options
    skiprows = set() if skiprows is None else set(skiprows)
MemoryError

如果我使用skiprows=1000000 运行它,它可以正常工作。如果我尝试skiprows=1500000,它会再次引发错误,这很奇怪,因为错误是在达到 2800000 之后开始的。在此之前它通过每 5000 个乘数没有问题。知道为什么会这样吗?

代码在我的个人电脑上运行良好:

df = pd.read_csv(filename, skiprows=2800000, nrows=5000, header=None)

df.memory_usage()
Out[25]: 
Index       72
0        40000
dtype: int64

编辑:

原来的循环是这样的:

current_chunk = 560 
chnksize = 5000

for chunk in range(current_chunk, 1000):
    df = pd.read_csv(filename, skiprows=chnksize*chunk, nrows=chnksize, header=None)
    out = "chunk_" + format(chunk, "06d")
    short_ids = df[0].str.slice(-11)

它从 API 查询 short_id 并将结果附加到文件中。但是我在顶部给出的代码段本身就会引发错误。

【问题讨论】:

  • 你能展示你的循环吗?
  • 对错误消息使用代码格式化按钮,而不是引用按钮。
  • @MaxU 我添加了循环(好吧,原始循环很长,所以我添加了我隔离错误的部分)——user2357112 修复了它。
  • @ayhan,你误用了skiprows参数,你应该使用chunksize
  • @MaxU 这实际上是我自己的不成功实施,这就是错字的原因。我知道我可以使用 pandas 的功能逐块读取,但我不知道我可以访问某个块,所以我使用的是 skiprows。

标签: python pandas memory


【解决方案1】:

Pandas 正在使用一种令人费解的内存密集型方式来实现 skiprows。在pandas.io.parsers.TextFileReader._clean_options:

if com.is_integer(skiprows):
    skiprows = lrange(skiprows)
skiprows = set() if skiprows is None else set(skiprows)

lrange(n)list(range(n)),所以这基本上是做skiprows = set(list(range(skiprows)))。它正在构建两个巨大的列表和一个集合,每个包含 280 万个整数!我想他们从没想过人们会尝试跳过这么多行。


如果您想分块读取文件,使用不同的skiprows 值重复调用read_csv 是一种低效的方法。您可以传递read_csv 一个chunksize 选项,然后以块的形式迭代返回的TextFileReader

In [138]: reader = pd.read_table('tmp.sv', sep='|', chunksize=4)

In [139]: reader
Out[139]: <pandas.io.parsers.TextFileReader at 0x121159a50>

In [140]: for chunk in reader:
   .....:     print(chunk)
   .....: 
   Unnamed: 0         0         1         2         3
0           0  0.469112 -0.282863 -1.509059 -1.135632
1           1  1.212112 -0.173215  0.119209 -1.044236
2           2 -0.861849 -2.104569 -0.494929  1.071804
3           3  0.721555 -0.706771 -1.039575  0.271860
   Unnamed: 0         0         1         2         3
0           4 -0.424972  0.567020  0.276232 -1.087401
1           5 -0.673690  0.113648 -1.478427  0.524988
2           6  0.404705  0.577046 -1.715002 -1.039268
3           7 -0.370647 -1.157892 -1.344312  0.844885
   Unnamed: 0         0        1         2         3
0           8  1.075770 -0.10905  1.643563 -1.469388
1           9  0.357021 -0.67460 -1.776904 -0.968914

或传递iterator=True 并使用get_chunk 获取指定大小的块:

In [141]: reader = pd.read_table('tmp.sv', sep='|', iterator=True)

In [142]: reader.get_chunk(5)
Out[142]: 
   Unnamed: 0         0         1         2         3
0           0  0.469112 -0.282863 -1.509059 -1.135632
1           1  1.212112 -0.173215  0.119209 -1.044236
2           2 -0.861849 -2.104569 -0.494929  1.071804
3           3  0.721555 -0.706771 -1.039575  0.271860
4           4 -0.424972  0.567020  0.276232 -1.087401

【讨论】:

  • 现在我已经完成了这 280 万行,有没有办法跳过一些块?是否需要调用 get_chunk(chunksize) n 次才能跳过 n 个块?
  • @ayhan:我不知道有什么更好的方法。您可以传递更大的块大小,但这可能会再次遇到内存问题。
【解决方案2】:

问题是skiprows 不会阻止将数据加载到内存中,从而导致内存错误。对于您的问题,您必须使用read_csvchunk 参数,而不是nrows

【讨论】:

  • 新版本更新了吗?
猜你喜欢
  • 2014-06-05
  • 2016-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-14
  • 1970-01-01
  • 2020-05-06
  • 1970-01-01
相关资源
最近更新 更多