以更快的方式将字符串列表转换为numpy数组
br
是一个字符串列表,内容大致是这样的:
['14 0.000000 -- (long term 0.000000)\n',
'19 0.000000 -- (long term 0.000000)\n',
'22 0.000000 -- (long term 0.000000)\n',
...
我对前两列数据感兴趣,想把它们转换成一个 numpy 数组。到目前为止,我想出了以下解决方案:
x = N.array ([0., 0.])
for i in br:
x = N.vstack ( (x, N.array (map (float, i.split ()[:2]))) )
这样做的结果是得到一个二维数组:
array([[ 0., 0.],
[ 14., 0.],
[ 19., 0.],
[ 22., 0.],
...
不过,由于 br
的数据量比较大(大约有 10 万条记录),这个过程需要一些时间。我在想,有没有办法在更短的时间内得到同样的结果呢?
3 个回答
1
将
map (float, i.split()[:2])
改成
map (float, i.split(' ',2)[:2])
可能会让程序运行得稍微快一点。因为你只关心每行中前两个用空格分开的部分,所以没有必要把整行都拆分开。这里的2
在i.split(' ',2)
中表示最多只拆分两次。举个例子,
In [11]: x='14 0.000000 -- (long term 0.000000)\n'
In [12]: x.split()
Out[12]: ['14', '0.000000', '--', '(long', 'term', '0.000000)']
In [13]: x.split(' ',2)
Out[13]: ['14', '0.000000', '-- (long term 0.000000)\n']
2
你可以尝试先处理一下字符串列表(比如用awk工具),如果这些字符串是从文件里来的,然后再用numpy.fromtxt来读取。如果你对获取这个列表的方式无能为力,还有几种选择:
- 放弃吧。如果你每天只运行这个功能一次,那速度就不是问题,你现在的解决方案已经足够好了。
- 用cython写一个输入输出插件。这样你可以大幅提升性能,因为你可以用C语言来处理所有的循环,并直接在一个很大的numpy数组(10^5行,2列)中修改值。
- 尝试用其他语言来解决你的问题。如果使用像C或Haskell这样的语言,你可以用ctypes从Python调用编译好的dll里的函数。
编辑
也许这种方法会稍微快一点:
def conv(mysrt):
return map(float, mystr.split()[:2])
br_float = map(conv, br)
x = N.array(br_float)
4
对我来说,这个方法快得多:
import numpy as N
br = ['14 0.000000 -- (long term 0.000000)\n']*50000
aa = N.zeros((len(br), 2))
for i,line in enumerate(br):
al, strs = aa[i], line.split(None, 2)[:2]
al[0], al[1] = float(strs[0]), float(strs[1])
改动如下:
- 提前分配好numpy数组(这个很重要)。你已经知道你需要一个特定尺寸的二维数组。
- 只对前两列使用split(),因为你不需要后面的内容。
- 不要使用map():它比列表推导式慢。我甚至没有用列表推导式,因为你知道只需要处理两列。
- 直接把数据放进提前分配好的数组里,而不是在循环时生成新的临时数组。