2016-01-21 113 views
9

NumPy阵列非常适合性能和易用性(更容易切片,索​​引比列表)。加速结构化NumPy阵列

我尝试构建一个NumPy structured array而不是dictNumPy arrays的数据容器。问题是性能差得多。使用同类数据约2.5倍,异构数据约32倍(我正在谈论NumPy数据类型)。

有没有办法加快结构化阵列的速度?我尝试将记忆顺序从'c'更改为'f',但这没有任何影响。

这里是我的分析代码:

import time 
import numpy as np 

NP_SIZE = 100000 
N_REP = 100 

np_homo = np.zeros(NP_SIZE, dtype=[('a', np.double), ('b', np.double)], order='c') 
np_hetro = np.zeros(NP_SIZE, dtype=[('a', np.double), ('b', np.int32)], order='c') 
dict_homo = {'a': np.zeros(NP_SIZE), 'b': np.zeros(NP_SIZE)} 
dict_hetro = {'a': np.zeros(NP_SIZE), 'b': np.zeros(NP_SIZE, np.int32)} 

t0 = time.time() 
for i in range(N_REP): 
    np_homo['a'] += i 

t1 = time.time() 
for i in range(N_REP): 
    np_hetro['a'] += i 

t2 = time.time() 
for i in range(N_REP): 
    dict_homo['a'] += i 

t3 = time.time() 
for i in range(N_REP): 
    dict_hetro['a'] += i 
t4 = time.time() 

print('Homogeneous Numpy struct array took {:.4f}s'.format(t1 - t0)) 
print('Hetoregeneous Numpy struct array took {:.4f}s'.format(t2 - t1)) 
print('Homogeneous Dict of numpy arrays took {:.4f}s'.format(t3 - t2)) 
print('Hetoregeneous Dict of numpy arrays took {:.4f}s'.format(t4 - t3)) 

编辑:忘了把我的时间数字:

Homogenious Numpy struct array took 0.0101s 
Hetoregenious Numpy struct array took 0.1367s 
Homogenious Dict of numpy arrays took 0.0042s 
Hetoregenious Dict of numpy arrays took 0.0042s 

EDIT2:我添加了一些额外的测试案例与TIMIT模块:

import numpy as np 
import timeit 

NP_SIZE = 1000000 

def time(data, txt, n_rep=1000): 
    def intern(): 
     data['a'] += 1 

    time = timeit.timeit(intern, number=n_rep) 
    print('{} {:.4f}'.format(txt, time)) 


np_homo = np.zeros(NP_SIZE, dtype=[('a', np.double), ('b', np.double)], order='c') 
np_hetro = np.zeros(NP_SIZE, dtype=[('a', np.double), ('b', np.int32)], order='c') 
dict_homo = {'a': np.zeros(NP_SIZE), 'b': np.zeros(NP_SIZE)} 
dict_hetro = {'a': np.zeros(NP_SIZE), 'b': np.zeros(NP_SIZE, np.int32)} 

time(np_homo, 'Homogeneous Numpy struct array') 
time(np_hetro, 'Hetoregeneous Numpy struct array') 
time(dict_homo, 'Homogeneous Dict of numpy arrays') 
time(dict_hetro, 'Hetoregeneous Dict of numpy arrays') 

结果于:

Homogeneous Numpy struct array 0.7989 
Hetoregeneous Numpy struct array 13.5253 
Homogeneous Dict of numpy arrays 0.3750 
Hetoregeneous Dict of numpy arrays 0.3744 

运行之间的比例似乎相当稳定。使用这两种方法和不同大小的数组。

对于offcase它的问题: 蟒蛇:3.4 NumPy的:1.9.2

+2

由于这个问题是关于NumPy的一个特定性能问题,而不是一般性的批评,因此它已经从Code Review迁移到Stack Overflow。 –

+0

如果你真的想使用结构化数组,我会建议尝试[pandas](http://pandas.pydata.org/)。 –

+1

看到这个问题:https://github.com/numpy/numpy/issues/6467 – MaxNoe

回答

2

在我的快速计时测试不同的是没有那么大:

In [717]: dict_homo = {'a': np.zeros(10000), 'b': np.zeros(10000)} 
In [718]: timeit dict_homo['a']+=1 
10000 loops, best of 3: 25.9 µs per loop 
In [719]: np_homo = np.zeros(10000, dtype=[('a', np.double), ('b', np.double)]) 
In [720]: timeit np_homo['a'] += 1 
10000 loops, best of 3: 29.3 µs per loop 

dict_homo的情况下,事实上,数组嵌入字典是一个小问题。这种简单的字典访问速度很快,基本上与通过变量名访问数组的方式相同。

因此,第一种情况下,它基本上是对1d阵列的测试+=

在结构化案例中,ab值在数据缓冲区中交替出现,因此np_homo['a']是一种“拉出”替代数字的视图。所以它会慢一点就不奇怪了。

In [721]: np_homo 
Out[721]: 
array([(41111.0, 0.0), (41111.0, 0.0), (41111.0, 0.0), ..., (41111.0, 0.0), 
     (41111.0, 0.0), (41111.0, 0.0)], 
     dtype=[('a', '<f8'), ('b', '<f8')]) 

二维数组也交错列值。

In [722]: np_twod=np.zeros((10000,2), np.double) 
In [723]: timeit np_twod[:,0]+=1 
10000 loops, best of 3: 36.8 µs per loop 

令人惊讶的是,它实际上比结构化案例慢一点。使用order='F'或(2,10000)形状可以加快速度,但仍然不如结构化的情况。

这些都是小测试时间,所以我不会做出重大索赔。但是结构化数组不会回头看。


另一次试验中,初始化所述阵列或字典新鲜每个步骤

In [730]: %%timeit np.twod=np.zeros((10000,2), np.double) 
np.twod[:,0] += 1 
    .....: 
10000 loops, best of 3: 36.7 µs per loop 
In [731]: %%timeit np_homo = np.zeros(10000, dtype=[('a', np.double), ('b', np.double)]) 
np_homo['a'] += 1 
    .....: 
10000 loops, best of 3: 38.3 µs per loop 
In [732]: %%timeit dict_homo = {'a': np.zeros(10000), 'b': np.zeros(10000)} 
dict_homo['a'] += 1 
    .....: 
10000 loops, best of 3: 25.4 µs per loop 

2d和结构更接近,具有稍微更好的性能的字典(1d)的情况下。我也尝试过np.ones,因为np.zeros可以延迟分配,但行为没有差异。

+0

嗯。那很有意思。特别是第一个结果。你是否尝试增加元素的大小?只是为了确保所需的时间不受某些常数的支配。 –