35

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

我有一个中等大小的 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 回答 5

46

是的,读取csv文件numpy非常慢。代码路径上有很多纯 Python。这些天来,即使我使用 pure 时,numpy我仍然使用pandasIO:

>>> 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 在这里写的东西:

>>> %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
于 2013-08-15T19:20:47.683 回答
7

如果您只想保存和读取一个 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
于 2013-08-15T19:19:47.597 回答
7

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

pandas.read_csv(filename)

确实是最快的解决方案(如果读取了超过 2000 个条目,那么在此之前,一切都在毫秒范围内)。它比 numpy 的变体高出大约 10 倍。(numpy.fromfile 在这里只是为了比较,它无法读取实际的 csv 文件。)

在此处输入图像描述

重现情节的代码:

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


b = perfplot.bench(
    setup=setup,
    kernels=[numpy_genfromtxt, numpy_loadtxt, numpy_fromfile, pandas_readcsv, kington],
    n_range=[2 ** k for k in range(23)],
)
b.save("out.png")
于 2020-01-23T10:38:13.847 回答
2

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

例如,我的特定代码可在此处获得。

于 2015-06-25T13:05:03.497 回答
1

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 模块很好。

于 2016-05-05T00:36:08.160 回答