0

次のpythonコードがあります:

H1 = [[0.04,0.03,0.01,0.002],[0.02,0.04,0.001,0.5]]
H2 = [[0.06,0.02,0.02,0.004],[0.8,0.09,0.6,0.1]]    

D1 = [0.01,0.02,0.1,0.01]    
D2 = [0.1,0.3,0.01,0.4] 

Tp = np.sum(D1)    
Tn = np.sum(D2) 

T = []    
append2 = T.append   
E = []    
append3 = E.append   

for h1,h2 in itertools.izip(H1,H2) 
    Err = []    
    append1 = Err.append
    for v in h1:    

        L1 = [1 if i>=v else 0 for i in h1]    
        L2 = [1 if i>=v else 0 for i in h2]    

        Sp = np.dot(D1,L1)     
        Sn = np.dot(D2,L2)    

        err = min(Sp+Tn-Sn, Sn+Tp-Sp)    
        append1(err)  

    b = np.argmin(Err)    
    append2(h1[b])    
    append3(Err[b])

これは単なるコード例です。内側の for ループを約 20,000 回近く実行する必要があります (ここでは 2 回だけ実行しています)。しかし、内側の for ループは非常に時間がかかり、実用的ではありません。行プロファイラーでは、その行が Sp = np.dot(D1,L1)表示され 、最も時間がかかります。上記のコードにかかる時間を短縮するにはどうすればよいですか。Sn = np.dot(D2,L2)b = np.argmin(Err)

どんな助けでも大歓迎です。

ありがとう!

4

4 に答える 4

4

リストの代わりに numpy 配列で numpy 関数を使用すると、かなり高速になります。ほとんどの numpy 関数は内部的にリストを配列に変換するため、実行時に多くのオーバーヘッドが追加されます。簡単な例を次に示します。

In [16]: a = range(10)

In [17]: b = range(10)

In [18]: aa = np.array(a)

In [19]: bb = np.array(b)

In [20]: %timeit np.dot(a, b)
10000 loops, best of 3: 54 us per loop

In [21]: %timeit np.dot(aa, bb)
100000 loops, best of 3: 3.4 us per loop

numpy.dotこの場合、配列で呼び出すと 16 倍速く実行されます。また、numpy 配列を使用すると、コードの一部を簡素化できるため、実行速度も向上します。たとえば、ifh1が配列の場合、次のL1 = [1 if i>=v else 0 for i in h1]ように記述できますh1 > v。これは配列を返し、実行速度も速くなります。以下では、リストを配列に置き換えて、それがどのように見えるかを確認できるようにしました。

import numpy as np

H1 = np.array([[0.04,0.03,0.01,0.002],[0.02,0.04,0.001,0.5]])
H2 = np.array([[0.06,0.02,0.02,0.004],[0.8,0.09,0.6,0.1]])

D1 = np.array([0.01,0.02,0.1,0.01])
D2 = np.array([0.1,0.3,0.01,0.4])

Tp = np.sum(D1)    
Tn = np.sum(D2) 

T = np.zeros(H1.shape[0])
E = np.zeros(H1.shape[0])

for i in range(len(H1)):
    h1 = H1[i]
    h2 = H2[i]
    Err = np.zeros(len(h1))

    for j in range(len(h1)):    
        v = h1[j]

        L1 = h1 > v
        L2 = h2 > v

        Sp = np.dot(D1, L1)     
        Sn = np.dot(D2, L2)    

        err = min(Sp+Tn-Sn, Sn+Tp-Sp)    
        Err[j] = err

    b = np.argmin(Err)
    T[i] = h1[b]
    E[i] = Err[b]

numpy 配列に慣れてきたら、少なくともブロードキャストを使用して内部ループを表現することを検討することをお勧めします。一部のアプリケーションでは、ブロードキャストを使用する方が Python ループよりもはるかに効率的です。頑張ってください。

于 2013-10-13T16:41:06.617 に答える
1

あなたのリストの内包表記には、いくつかの簡単な果物があります。

L1 = [1 if i>=v else 0 for i in h1]
L2 = [1 if i>=v else 0 for i in h2]

上記は次のように記述できます。

L1 = [i>=v for i in h1]
L2 = [i>=v for i in h2]

ブール値は整数のサブクラスであり、すでに 1 と 0 であるためTrueFalseおしゃれな服を着ているだけです。

err = min(Sp+Tn-Sn, Sn+Tp-Sp)    
append1(err)  

上記の 2 行を組み合わせて、変数の割り当てとアクセスを回避できます。

コードを関数に入れると、すべてのローカル変数の使用がわずかに速くなります。また、使用するグローバル関数またはメソッド (minなどnp.dot) は、デフォルトの引数を使用して関数シグネチャでローカルに変換できます。np.dot属性のルックアップが含まれるため、(操作自体にかかる時間を除けば) 呼び出すのに特に時間がかかります。appendこれは、リストメソッドで既に行っている最適化に似ています。

あなたの質問は本当に「どうすればNumPyを高速化できますか?」(他の人はあなたのために上にあります)しかし、それらはいくらかの影響を与え、やる価値があるかもしれません.

于 2013-10-13T15:47:11.603 に答える