【问题标题】:loading csv column into numpy memmap (fast)将 csv 列加载到 numpy memmap 中(快速)
【发布时间】:2016-08-14 22:43:38
【问题描述】:

我有一个包含两列的 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),加载和解析 numpy 需要半个多小时(每 1000 行 21.5 毫秒)。

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


问题

有什么方便的方法吗? 使用Linux,我可以tail 去掉标题,cut 去掉第二列,但我仍然需要在将值写入磁盘上的二进制文件之前解析字符串表示:

$ 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 命令用于解析浮点数的字符串表示并将它们写入磁盘

【问题讨论】:

  • 无论发生什么,您至少需要将整个 csv 文件 通过 内存才能将其转换为二进制格式,但这仍然比将其全部保存在那里有所改进是一次。
  • 您是否考虑过编写一个简单的 C 程序来生成二进制文件?
  • 是的,我考虑过,我只是想知道是否已经有这样的程序。永远不要费心重新发明轮子......

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


【解决方案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

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

【讨论】:

    【解决方案2】:

    由于您的数据在磁盘上,因此您必须先导入它,而且成本很高。

    我认为当今最好的 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 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-09
      • 1970-01-01
      • 2016-08-14
      • 2015-09-10
      • 2019-02-13
      • 1970-01-01
      相关资源
      最近更新 更多