我有一个以下格式的文本文件,其中每一行用换行符分隔
a 0.418 0.24968 -0.41242 0.1217 0.34527 -0.044457 -0.49688 -0.17862 -0.00066023 -0.6566
b 0.013441 0.23682 -0.16899 0.40951 0.63812 0.47709 -0.42852 -0.55641 -0.364 -0.23938
c 0.15164 0.30177 -0.16763 0.17684 0.31719 0.33973 -0.43478 -0.31086 -0.44999 -0.29486
我正在尝试将每行的数字组件加载到形状为3x10的numpy数组中。这是我一直在使用的方法。
embeddings = np.empty((0, 50))
for line in f :
splitLine = line.rstrip().split()
res = splitLine[1:]
embeddings = np.append(embeddings, [res], axis=0)
然而,当行数增加时(我有一个包含400000行的文本文件),这种方法变得非常耗时。
是否有更有效的方法将数值加载到numpy数组?
答案 0 :(得分:0)
使用Pandas'read_table
代替,然后将DataFrame转换为您需要的numpy数组。它会比尝试拆分字符串并逐行组装数组更快更干净。
答案 1 :(得分:0)
是的,这是因为numpy
数组是固定大小的,np.append
是O(N)操作。最好的办法是加载到列表中,然后使用该列表创建numpy.array
。如果该列表可能变得太大并且给你带来内存问题,那么只需使用np.fromiter
,它就会比你的方法更慢,但比加载到列表中的内存效率更高。首先,一些设置:
>>> s = """a 0.418 0.24968 -0.41242 0.1217 0.34527 -0.044457 -0.49688 -0.17862 -0.00066023 -0.6566
... b 0.013441 0.23682 -0.16899 0.40951 0.63812 0.47709 -0.42852 -0.55641 -0.364 -0.23938
... c 0.15164 0.30177 -0.16763 0.17684 0.31719 0.33973 -0.43478 -0.31086 -0.44999 -0.29486"""
>>>
>>> import io
>>> import numpy as np
最后,尝试将count
参数传递给np.fromiter
:
>>> import csv
>>> with io.StringIO(s) as f: # fake a file
... reader = csv.reader(f, delimiter=' ')
... vals = (float(x) for row in reader for x in row[1:])
... arr = np.fromiter(vals, count=10*3, dtype=float)
...
>>> arr
array([ 0.418 , 0.24968 , -0.41242 , 0.1217 , 0.34527 ,
-0.044457 , -0.49688 , -0.17862 , -0.00066023, -0.6566 ,
0.013441 , 0.23682 , -0.16899 , 0.40951 , 0.63812 ,
0.47709 , -0.42852 , -0.55641 , -0.364 , -0.23938 ,
0.15164 , 0.30177 , -0.16763 , 0.17684 , 0.31719 ,
0.33973 , -0.43478 , -0.31086 , -0.44999 , -0.29486 ])
最后,假设您知道尺寸,将形状更改为您需要的形状:
>>> arr.shape = (3, 10)
>>> arr
array([[ 0.418 , 0.24968 , -0.41242 , 0.1217 , 0.34527 ,
-0.044457 , -0.49688 , -0.17862 , -0.00066023, -0.6566 ],
[ 0.013441 , 0.23682 , -0.16899 , 0.40951 , 0.63812 ,
0.47709 , -0.42852 , -0.55641 , -0.364 , -0.23938 ],
[ 0.15164 , 0.30177 , -0.16763 , 0.17684 , 0.31719 ,
0.33973 , -0.43478 , -0.31086 , -0.44999 , -0.29486 ]])
如果不提前知道行数,您可以快速首先通过并计算它们,例如:
>>> with io.StringIO(s) as f:
... num_rows = sum(1 for row in f)
...
>>> num_rows
3
答案 2 :(得分:0)
numpy
中的普通加载器为loadtxt
和genfromtxt
。在这种情况下,两者都易于使用:
In [129]: lines = b"""a 0.418 0.24968 -0.41242 0.1217 0.34527 -0.044457 -0.49688
...: -0.17862 -0.00066023 -0.6566
...: b 0.013441 0.23682 -0.16899 0.40951 0.63812 0.47709 -0.42852 -0.55641
...: -0.364 -0.23938
...: c 0.15164 0.30177 -0.16763 0.17684 0.31719 0.33973 -0.43478 -0.31086 -
...: 0.44999 -0.29486"""
In [130]: lines = lines.splitlines()
由于您对第一栏不感兴趣,我们可以跳过它:
In [134]: arr = np.genfromtxt(lines,usecols=range(1,11))
In [135]: arr
Out[135]:
array([[ 0.418 , 0.24968 , -0.41242 , 0.1217 , 0.34527 ,
-0.044457 , -0.49688 , -0.17862 , -0.00066023, -0.6566 ],
[ 0.013441 , 0.23682 , -0.16899 , 0.40951 , 0.63812 ,
0.47709 , -0.42852 , -0.55641 , -0.364 , -0.23938 ],
[ 0.15164 , 0.30177 , -0.16763 , 0.17684 , 0.31719 ,
0.33973 , -0.43478 , -0.31086 , -0.44999 , -0.29486 ]])
这将逐行读取文件(此处使用行列表进行模拟),解析每个文件并将结果累积到列表中。这比每次附加到数组要快。
为了更快地使用pandas
阅读器 - 它同时具有C和Python引擎。
In [140]: pd.read_csv(BytesIO(b'\n'.join(lines)), delim_whitespace=True,header=N
...: one,usecols=range(1,11)).values
Out[140]:
array([[ 0.418 , 0.24968 , -0.41242 , 0.1217 , 0.34527 ,
-0.044457 , -0.49688 , -0.17862 , -0.00066023, -0.6566 ],
[ 0.013441 , 0.23682 , -0.16899 , 0.40951 , 0.63812 ,
0.47709 , -0.42852 , -0.55641 , -0.364 , -0.23938 ],
[ 0.15164 , 0.30177 , -0.16763 , 0.17684 , 0.31719 ,
0.33973 , -0.43478 , -0.31086 , -0.44999 , -0.29486 ]])
至少每个人都声称大熊猫的速度更快 - 对于这个小样本来说,它不是:
In [141]: timeit pd.read_csv(BytesIO(b'\n'.join(lines)), delim_whitespace=True,h
...: eader=None,usecols=range(1,11)).values
1.31 ms ± 18.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [142]: timeit arr = np.genfromtxt(lines,usecols=range(1,11))
380 µs ± 17.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)