10

我正在使用 pandas 来管理一个由 8 字节整数组成的大型数组。这些整数作为逗号分隔的 CSV 文件中列的空格分隔元素包含在内,数组大小约为 10000x10000。

Pandas 能够从前几列中快速读取逗号分隔的数据作为 DataFrame,并以最小的麻烦快速将空格分隔的字符串存储在另一个 DataFrame 中。当我尝试将表格从以空格分隔的字符串的单列转换为 8 位整数的 DataFrame 时,问题就来了。

我尝试了以下方法:

intdata = pd.DataFrame(strdata.columnname.str.split().tolist(), dtype='uint8')

但是内存使用是无法忍受的——10MB 的整数会消耗 2GB 的内存。我被告知这是语言的限制,在这种情况下我无能为力。

作为一种可能的解决方法,建议我将字符串数据保存到 CSV 文件,然后将 CSV 文件重新加载为以空格分隔的整数的 DataFrame。这很好用,但为了避免写入磁盘导致的减速,我尝试写入 StringIO 对象。

这是一个最小的非工作示例:

import numpy as np
import pandas as pd
from cStringIO import StringIO

a = np.random.randint(0,256,(10000,10000)).astype('uint8')
b = pd.DataFrame(a)
c = StringIO()
b.to_csv(c, delimiter=' ', header=False, index=False)
d = pd.io.parsers.read_csv(c, delimiter=' ', header=None, dtype='uint8')

这会产生以下错误消息:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.7/site-packages/pandas/io/parsers.py", line 443, in parser_f
    return _read(filepath_or_buffer, kwds)
  File "/usr/lib64/python2.7/site-packages/pandas/io/parsers.py", line 228, in _read
    parser = TextFileReader(filepath_or_buffer, **kwds)
  File "/usr/lib64/python2.7/site-packages/pandas/io/parsers.py", line 533, in __init__
    self._make_engine(self.engine)
  File "/usr/lib64/python2.7/site-packages/pandas/io/parsers.py", line 670, in _make_engine
    self._engine = CParserWrapper(self.f, **self.options)
  File "/usr/lib64/python2.7/site-packages/pandas/io/parsers.py", line 1032, in __init__
    self._reader = _parser.TextReader(src, **kwds)
  File "parser.pyx", line 486, in pandas.parser.TextReader.__cinit__ (pandas/parser.c:4494)
ValueError: No columns to parse from file

'c.csv'这令人费解,因为如果我使用而不是运行完全相同的代码c,则代码可以完美运行。另外,如果我使用以下代码段:

file = open('c.csv', 'w')
file.write(c.getvalue())

保存 CSV 文件没有任何问题,因此写入 StringIO 对象不是问题。

我可能需要在 read_csv 行中替换cc.getvalue(),但是当我这样做时,解释器会尝试c在终端中打印 的内容!当然有办法解决这个问题。

在此先感谢您的帮助。

4

1 回答 1

16

这里有两个问题,一个是基本问题,一个是您还没有遇到过的问题。:^)

首先,在您写入 之后c,您处于(虚拟)文件的末尾。你需要seek回到起点。我们将使用较小的网格作为示例:

>>> a = np.random.randint(0,256,(10,10)).astype('uint8')
>>> b = pd.DataFrame(a)
>>> c = StringIO()
>>> b.to_csv(c, delimiter=' ', header=False, index=False)
>>> next(c)
Traceback (most recent call last):
  File "<ipython-input-57-73b012f9653f>", line 1, in <module>
    next(c)
StopIteration

这会产生“无列”错误。但是,如果我们seek首先:

>>> c.seek(0)
>>> next(c)
'103,3,171,239,150,35,224,190,225,57\n'

但是现在你会注意到第二个问题——逗号?我以为我们要求使用空格分隔符?但to_csv只收sep,不收delimiter。在我看来,它应该要么接受它,要么反对它不接受它,但默默地忽略它感觉就像一个错误。无论如何,如果我们使用sep(或delim_whitespace=True):

>>> a = np.random.randint(0,256,(10,10)).astype('uint8')
>>> b = pd.DataFrame(a)
>>> c = StringIO()
>>> b.to_csv(c, sep=' ', header=False, index=False)
>>> c.seek(0)
>>> d = pd.read_csv(c, sep=' ', header=None, dtype='uint8')
>>> d
     0    1    2    3    4    5    6    7    8    9
0  209   65  218  242  178  213  187   63  137  145
1  161  222   50   92  157   31   49   62  218   30
2  182  255  146  249  115   91  160   53  200  252
3  192  116   87   85  164   46  192  228  104  113
4   89  137  142  188  183  199  106  128  110    1
5  208  140  116   50   66  208  116   72  158  169
6   50  221   82  235   16   31  222    9   95  111
7   88   36  204   96  186  205  210  223   22  235
8  136  221   98  191   31  174   83  208  226  150
9   62   93  168  181   26  128  116   92   68  153
于 2014-07-03T21:53:53.650 回答