将csv列加载到numpy memmap中(快速)

时间:2016-04-21 15:45:06

标签: python linux csv numpy memory-mapped-files

我有一个带有两列的csv文件,用示波器保存测量结果:

Model,MSO4034
Firmware Version,2.48
# ... (15 lines of header) ...
-5.0000000e-02,-0.0088
-4.9999990e-02,0.0116
-4.9999980e-02,0.006
-4.9999970e-02,-0.0028
-4.9999960e-02,-0.002
-4.9999950e-02,-0.0028
-4.9999940e-02,0.0092
-4.9999930e-02,-0.0072
-4.9999920e-02,-0.0008
-4.9999910e-02,-0.0056

这个数据我想加载到一个numpy数组中。我可以使用np.loadtxt

np.loadtxt('data.csv', delimiter=',', skiprows=15, usecols=[1])

但是,我的数据文件很大(100个MSamples),加载和解析需要花费半个多小时(每1000行21.5毫秒)。

我首选的方法是直接为numpy创建一个Memory Map文件,该文件只包含二进制值,连接成一个文件。它基本上是内存中的数组,只是它在内存中而在磁盘上。

问题

有没有方便的方法呢? 使用Linux,我可以tail将标题和cut排除在第二列之外,但在将其写入磁盘上的二进制文件之前,我仍然需要解析值字符串表示: / p>

$ tail -n +16 data.csv | cut -d',' -f2
-0.0088
0.0116
0.006
-0.0028
-0.002
-0.0028
0.0092
-0.0072
-0.0008
-0.0056

是否有任何Linux命令用于解析浮点数的字符串表示并将其写入磁盘

2 个答案:

答案 0 :(得分:1)

我还建议使用Pandas的CSV解析器,但不是一次性将整个文件读入内存,而是将其重复遍历并将其写入内存映射数组:

import numpy as np
from numpy.lib.format import open_memmap
import pandas as pd

# make some test data
data = np.random.randn(100000, 2)
np.savetxt('/tmp/data.csv', data, delimiter=',', header='foo,bar')

# we need to specify the shape and dtype in advance, but it would be cheap to
# allocate an array with more rows than required since memmap files are sparse.
mmap = open_memmap('/tmp/arr.npy', mode='w+', dtype=np.double, shape=(100000, 2))

# parse at most 10000 rows at a time, write them to the memmaped array
n = 0
for chunk in pd.read_csv('/tmp/data.csv', chunksize=10000):
    mmap[n:n+chunk.shape[0]] = chunk.values
    n += chunk.shape[0]

print(np.allclose(data, mmap))
# True

您可以根据一次可以容纳在内存中的文件大小来调整块大小。请记住,在解析块时,您需要保留原始文本以及转换后的内存值。

答案 1 :(得分:0)

由于您的数据位于磁盘上,因此您必须先将其导入,但成本会很高。

我认为今天最好的csv阅读器是pandas

In [7]: %timeit v=pd.read_csv('100ksamples.csv',sep=',')
1 loop, best of 3: 276 ms per loop # for 100k lines

似乎比你的测试好10倍(但它取决于磁盘)。

之后,您可以使用pickle之类的工具以二进制模式保存并节省时间。

In [8]: %timeit with open('e.pk','bw') as f : pickle.dump(v,f)
100 loops, best of 3: 16.2 ms per loop

In [9]: %timeit with open('e.pk','br') as f : v2=pickle.load(f)
100 loops, best of 3: 8.64 ms per loop