使用np.fromiter读取大型ASCII作为numpy数组时指定不同的dtypes

时间:2016-12-01 11:43:14

标签: python arrays numpy multidimensional-array

我正在尝试实现this answer中给出的解决方案,将我的~3.3GB ASCII读入ndarray

实际上,当我对我的文件使用此函数时,我得到MemoryError

def iter_loadtxt(filename, delimiter=None, skiprows=0, dtype=float):
    def iter_func():
        with open(filename, 'r') as infile:
            for _ in range(skiprows):
                next(infile)
            for line in infile:
                line = line.rstrip().split(delimiter)
                for item in line:
                    yield dtype(item)
        iter_loadtxt.rowlength = len(line)

    data = np.fromiter(iter_func(), dtype=[('',np.float),('',np.float),('',np.float),('',np.int),('',np.int),('',np.int),('',np.int)])
    data = data.reshape((-1, iter_loadtxt.rowlength))
    return data

data = iter_loadtxt(fname,skiprows=1)

我现在正试图在np.fromiter的调用中输入不同的dtypes,希望如果我的大多数列是整数而不是浮点数,我将有足够的运气来避免内存问题,但我没有到目前为止的成功。

我的文件是"很多行" X 7 cols,我想指定以下格式:前三个col的float和以下uint。我的操作系统是Windows 10 64位,我有8GB的RAM。我使用的是python 2.7 32bit。

我的尝试是(this answer之后):

data = np.fromiter(iter_func(), dtype=[('',np.float),('',np.float),('',np.float),('',np.int),('',np.int),('',np.int),('',np.int)])

但我收到TypeError: expected a readable buffer object

EDIT1

感谢提供解决方案的 hpaulj 。以下是工作代码。

def iter_loadtxt(filename, delimiter=None, skiprows=0, dtype=float):
    def iter_func():
        dtypes = [float, float, float, int, int, int, int]
        with open(filename, 'r') as infile:
            for _ in range(skiprows):
                next(infile)
            for line in infile:
                line = line.rstrip().split(delimiter)
                values = [t(v) for t, v in zip(dtypes, line)]
                yield tuple(values)
        iter_loadtxt.rowlength = len(line)

    data = np.fromiter(iter_func(), dtype=[('',np.float),('',np.float),('',np.float),('',np.int),('',np.int),('',np.int),('',np.int)])

    return data

data = iter_loadtxt(fname,skiprows=1)

1 个答案:

答案 0 :(得分:1)

如果输入文件足够大,任何代码(无论如何简化)都会出现内存错误。

对于所有浮点数,您的7列数组将占用56个字节;与混合dtype 40.不完全是一个很大的变化。如果它之前通过文件的1/3击中内存错误,它现在会命中它(理论上是1/2)。

iter_func读取文件,并提供稳定的浮动流(它自己的dtype)。它不返回按行分组的浮点数。它保留了一些行数,最后用它来重塑1d数组。

fromiter可以处理复合dtype,但前提是它为它提供了适当大小的元组。

In [342]: np.fromiter([(1,2),(3,4),(5,6)],dtype=np.dtype('i,i'))
Out[342]: 
array([(1, 2), (3, 4), (5, 6)], 
      dtype=[('f0', '<i4'), ('f1', '<i4')])

In [343]: np.fromiter([1,2,3,4],dtype=np.dtype('i,i'))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-343-d0fc5f822886> in <module>()
----> 1 np.fromiter([1,2,3,4],dtype=np.dtype('i,i'))

TypeError: a bytes-like object is required, not 'int'

iter_func更改为此类内容可能有效(未经测试):

def iter_func():
    dtypes=[float,float,float,int,int,int,int]
    with open(filename, 'r') as infile:
        for _ in range(skiprows):
            next(infile)
        for line in infile:
            line = line.rstrip().split(delimiter)
            values = [t(v) for t,v in zip(dtypes, line)]
            yield tuple(values)
arr = np.fromiter(iter_func, dtype=[('',np.float),('',np.float),('',np.float),('',np.int),('',np.int),('',np.int),('',np.int)] )