20

コードの最適化を何度も試みた結果、最後のリソースは、複数のコアを使用して以下のコードを実行することであると思われます。複数のコアを使用してより高速に実行できるように、コードを変換/再構築する方法が正確にはわかりません。最終目標を達成するためのガイダンスを得ることができれば幸いです。最終的な目標は、各配列が約 700,000 要素を保持する配列 A および B に対して、このコードをできるだけ速く実行できるようにすることです。これは、小さな配列を使用したコードです。700k 要素の配列はコメントアウトされています。

import numpy as np

def ismember(a,b):
    for i in a:
        index = np.where(b==i)[0]
        if index.size == 0:
            yield 0
        else:
            yield index


def f(A, gen_obj):
    my_array = np.arange(len(A))
    for i in my_array:
        my_array[i] = gen_obj.next()
    return my_array


#A = np.arange(700000)
#B = np.arange(700000)
A = np.array([3,4,4,3,6])
B = np.array([2,5,2,6,3])

gen_obj = ismember(A,B)

f(A, gen_obj)

print 'done'
# if we print f(A, gen_obj) the output will be: [4 0 0 4 3]
# notice that the output array needs to be kept the same size as array A.

私がやろうとしているのは、ismember [2] と呼ばれる MATLAB 関数を模倣することです (次のようにフォーマットされているもの: 。部分のみ[Lia,Locb] = ismember(A,B)を取得しようとしています。Locb

Matlab から: Locb には、B のメンバーである A の各値の B の最小インデックスが含まれます。出力配列 Locb には、A が B のメンバーでない場合は常に 0 が含まれます。

主な問題の 1 つは、この操作をできるだけ効率的に実行できるようにする必要があることです。テストのために、700k 要素の 2 つの配列があります。ジェネレーターを作成し、ジェネレーターの値を調べても、仕事が速く完了しないようです。

4

5 に答える 5

18

複数のコアについて心配する前に、辞書を使用して ismember 関数の線形スキャンを排除します。

def ismember(a, b):
    bind = {}
    for i, elt in enumerate(b):
        if elt not in bind:
            bind[elt] = i
    return [bind.get(itm, None) for itm in a]  # None can be replaced by any other "not in b" value

元の実装では、A の各要素に対して B の要素を完全にスキャンする必要があり、それをO(len(A)*len(B)). 上記のコードでは、dict Bset を生成するために B を 1 回完全にスキャンする必要があります。dict を使用することで、A の各要素に対して B の各要素のルックアップを効果的に行い、操作をO(len(A)+len(B)). それでも遅すぎる場合は、上記の関数を複数のコアで実行することを心配してください。

編集:インデックス作成も少し変更しました。すべての配列がインデックス 1 から始まるため、Matlab は 0 を使用します。Python/numpy は配列を 0 から開始するため、データ セットの場合は次のようになります。

A = [2378, 2378, 2378, 2378]
B = [2378, 2379]

要素がない場合に 0 を返すと、結果は A のすべての要素を除外します。上記のルーチンはNone、0 ではなくインデックスがない場合に返します。-1 を返すことはオプションですが、Python はそれを配列の最後の要素であると解釈します。 None配列へのインデックスとして使用された場合、例外が発生します。別の動作が必要な場合は、式の 2 番目の引数を、Bind.get(item,None)返される値に変更します。

于 2013-04-07T15:59:41.203 に答える
15

sfstewman の優れた回答が問題を解決した可能性が最も高いです。

numpy だけで同じことを達成する方法を追加したいと思います。

numpy独自in1d関数を利用しています。

B_unique_sorted, B_idx = np.unique(B, return_index=True)
B_in_A_bool = np.in1d(B_unique_sorted, A, assume_unique=True)
  • B_unique_sortedBソートされた一意の値が含まれています。
  • B_idxは、これらの値に対して元の へのインデックスを保持しますB
  • B_in_A_boolB_unique_sortedの値が にあるかどうかを格納するのサイズのブール配列B_unique_sortedですA
    注:に関して出力を返す必要があるため、A で (B からの一意の値)を探す必要があります。B_idx
    注:A既に一意であると想定しています。

B_in_A_boolこれで、共通の値を取得するために使用できます

B_unique_sorted[B_in_A_bool]

および元のそれぞれのインデックスB

B_idx[B_in_A_bool]

最後に、テストはしていませんが、これは純粋な Python の for ループよりも大幅に高速であると思います。

于 2013-04-07T19:30:59.050 に答える
1

リスト内包表記を使用してみてください。

In [1]: import numpy as np

In [2]: A = np.array([3,4,4,3,6])

In [3]: B = np.array([2,5,2,6,3])

In [4]: [x for x in A if not x in B]
Out[4]: [4, 4]

一般に、リスト内包表記は for ループよりもはるかに高速です。

等しい長さのリストを取得するには;

In [19]: map(lambda x: x if x not in B else False, A)
Out[19]: [False, 4, 4, False, False]

これは、小さなデータセットでは非常に高速です。

In [20]: C = np.arange(10000)

In [21]: D = np.arange(15000, 25000)

In [22]: %timeit map(lambda x: x if x not in D else False, C)
1 loops, best of 3: 756 ms per loop

大規模なデータセットの場合は、 を使用multiprocessing.Pool.map()して操作を高速化できます。

于 2013-04-07T15:57:50.150 に答える