2016-01-21 29 views
9

NumPy配列は、パフォーマンスと使いやすい(リストよりも簡単なスライシング、インデックス作成)の両方に最適です。構造化NumPy配列を高速化

dictの代わりにNumPy structured arrayのデータコンテナを構築しようとしました。NumPy arraysです。問題はパフォーマンスがずっと悪いことです。同種のデータを使用すると約2.5倍、異種のデータは約32倍です(私はNumPyのデータ型について話しています)。

構造化アレイのスピードを上げる方法はありますか?私はmemoryorderを '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にとっては重要: のpython:3.4 numpyの:1.9.2

+2

この質問は一般的な批判ではなく、NumPyの特定のパフォーマンス問題について質問しているので、コードレビューからスタックオーバーフローに移行されています。 –

+0

構造化配列を実際に使いたい場合は、[pandas](http://pandas.pydata.org/)を試してみることをお勧めします。 –

+1

この問題を参照してください:https://github.com/numpy/numpy/issues/6467 – MaxNoe

答えて

2

私の迅速なタイミングの差はそれほど大きくないテスト:dict_homo場合

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 

、配列が辞書に埋め込まれているという事実は小さな点です。このような単純な辞書アクセスは高速で、基本的に変数名で配列にアクセスするのと同じです。

したがって、最初のケースでは基本的に1dアレイの場合は+=のテストです。

構造化されたケースでは、とbの値がデータバッファ内で交互に表示されるため、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')]) 

2d配列も列値をインターリーブします。

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.zerosは割り当てを遅延させることができますが、動作に違いはありませんので、np.onesで試してみました。

+0

Hmm。それは面白い。特に最初の結果。あなたは要素のサイズを増やそうとしましたか?必要な時間が一定ではないことを確かめるだけです。 –

関連する問題