与Matlab相比,Numpy加载csv TOO变慢

时间:2013-08-15 18:38:39

标签: python matlab csv numpy

我发布了这个问题,因为我想知道我是否做了一些非常错误的结果。

我有一个中等大小的csv文件,我尝试使用numpy来加载它。为了说明,我使用python创建了文件:

import timeit
import numpy as np

my_data = np.random.rand(1500000, 3)*10
np.savetxt('./test.csv', my_data, delimiter=',', fmt='%.2f')

然后,我尝试了两种方法:numpy.genfromtxt,numpy.loadtxt

setup_stmt = 'import numpy as np'
stmt1 = """\
my_data = np.genfromtxt('./test.csv', delimiter=',')
"""
stmt2 = """\
my_data = np.loadtxt('./test.csv', delimiter=',')
"""

t1 = timeit.timeit(stmt=stmt1, setup=setup_stmt, number=3)
t2 = timeit.timeit(stmt=stmt2, setup=setup_stmt, number=3)

结果显示 t1 = 32.159652940464184,t2 = 52.00093725634724
但是,当我尝试使用matlab时:

tic
for i = 1:3
    my_data = dlmread('./test.csv');
end
toc

结果显示:经过的时间 3.196465秒

我知道加载速度可能存在一些差异,但是:

  1. 这远远超出我的预期;
  2. 是不是np.loadtxt应该比np.genfromtxt快?
  3. 我还没有尝试过python csv模块,因为加载csv文件是我经常做的事情,使用csv模块,编码有点冗长......但是我很乐意尝试它,如果那样的话唯一的办法。目前我更担心的是我做错了什么。
  4. 任何输入都将不胜感激。非常感谢提前!

5 个答案:

答案 0 :(得分:41)

是的,将csv个文件读入numpy非常慢。代码路径中有很多纯Python。这些天,即使我使用纯numpy,我仍然使用pandas作为IO:

>>> import numpy as np, pandas as pd
>>> %time d = np.genfromtxt("./test.csv", delimiter=",")
CPU times: user 14.5 s, sys: 396 ms, total: 14.9 s
Wall time: 14.9 s
>>> %time d = np.loadtxt("./test.csv", delimiter=",")
CPU times: user 25.7 s, sys: 28 ms, total: 25.8 s
Wall time: 25.8 s
>>> %time d = pd.read_csv("./test.csv", delimiter=",").values
CPU times: user 740 ms, sys: 36 ms, total: 776 ms
Wall time: 780 ms

或者,在这个简单的案例中,你可以使用像Joe Kington写的那样here

>>> %time data = iter_loadtxt("test.csv")
CPU times: user 2.84 s, sys: 24 ms, total: 2.86 s
Wall time: 2.86 s

还有Warren Weckesser的textreader库,以防pandas过于依赖:

>>> import textreader
>>> %time d = textreader.readrows("test.csv", float, ",")
readrows: numrows = 1500000
CPU times: user 1.3 s, sys: 40 ms, total: 1.34 s
Wall time: 1.34 s

答案 1 :(得分:5)

如果您只想保存并读取numpy数组,那么根据大小将其保存为二进制或压缩二进制文件要好得多:

my_data = np.random.rand(1500000, 3)*10
np.savetxt('./test.csv', my_data, delimiter=',', fmt='%.2f')
np.save('./testy', my_data)
np.savez('./testz', my_data)
del my_data

setup_stmt = 'import numpy as np'
stmt1 = """\
my_data = np.genfromtxt('./test.csv', delimiter=',')
"""
stmt2 = """\
my_data = np.load('./testy.npy')
"""
stmt3 = """\
my_data = np.load('./testz.npz')['arr_0']
"""

t1 = timeit.timeit(stmt=stmt1, setup=setup_stmt, number=3)
t2 = timeit.timeit(stmt=stmt2, setup=setup_stmt, number=3)
t3 = timeit.timeit(stmt=stmt3, setup=setup_stmt, number=3)

genfromtxt 39.717250824
save 0.0667860507965
savez 0.268463134766

答案 2 :(得分:1)

也许最好安排一个简单的c代码,它将数据转换为二进制文件并且“numpy”读取二进制文件。我有一个20GB的CSV文件要读取,CSV数据是int,double,str的混合。 Numpy读取数组结构需要一个多小时,而转储到二进制大约需要2分钟,加载到numpy需要不到2秒!

例如,我的具体代码可用here

答案 3 :(得分:1)

我已经用perfplot(属于我的一个小项目)对建议的解决方案进行了性能测试,发现

pandas.read_csv(filename)

确实是最快的解决方案(如果读取的条目超过2000个,则所有内容都在毫秒范围内)。它的性能要比numpy的变体高出约10倍。(numpy.fromfile仅用于比较,它无法读取实际的csv文件。)

enter image description here

用于重现情节的代码:

import numpy
import pandas
import perfplot

numpy.random.seed(0)
filename = "a.txt"


def setup(n):
    a = numpy.random.rand(n)
    numpy.savetxt(filename, a)
    return None


def numpy_genfromtxt(data):
    return numpy.genfromtxt(filename)


def numpy_loadtxt(data):
    return numpy.loadtxt(filename)


def numpy_fromfile(data):
    out = numpy.fromfile(filename, sep=" ")
    return out


def pandas_readcsv(data):
    return pandas.read_csv(filename, header=None).values.flatten()


def kington(data):
    delimiter = " "
    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)
        kington.rowlength = len(line)

    data = numpy.fromiter(iter_func(), dtype=dtype).flatten()
    return data


perfplot.show(
    setup=setup,
    kernels=[numpy_genfromtxt, numpy_loadtxt, numpy_fromfile, pandas_readcsv, kington],
    n_range=[2 ** k for k in range(20)],
    logx=True,
    logy=True,
)

答案 4 :(得分:0)

FWIW内置的csv模块工作得很好而且真的不是那么冗长。

csv模块:

%%timeit
with open('test.csv', 'r') as f:
    np.array([l for l in csv.reader(f)])


1 loop, best of 3: 1.62 s per loop

np.loadtext

%timeit np.loadtxt('test.csv', delimiter=',')

1 loop, best of 3: 16.6 s per loop

pd.read_csv

%timeit pd.read_csv('test.csv', header=None).values

1 loop, best of 3: 663 ms per loop

我个人喜欢使用pandas read_csv,但是当我使用纯粹的numpy时,csv模块很不错。