17

itertools.product を使用して、長さ 13 の 4 つの要素のすべての可能なバリエーションを生成します。4 と 13 は任意ですが、そのままでは 4^13 の結果が得られます。これは大量です。Numpy 配列としての結果が必要で、現在次のことを行っています。

  c = it.product([1,-1,np.complex(0,1), np.complex(0,-1)], repeat=length)
  sendbuf = np.array(list(c))

いくつかの単純なプロファイリング コードが間に押し込まれているため、最初の行はほぼ瞬時に表示されるように見えますが、リストへの変換と Numpy 配列への変換には約 3 時間かかります。これを速くする方法はありますか?私が見落としているのは、おそらく本当に明白なことです。

ありがとう!

4

6 に答える 6

19

に相当する NumPy はitertools.product()is ですがnumpy.indices()、0,...,k-1 の形式の範囲の積しか得られません。

numpy.rollaxis(numpy.indices((2, 3, 3)), 0, 4)
array([[[[0, 0, 0],
         [0, 0, 1],
         [0, 0, 2]],

        [[0, 1, 0],
         [0, 1, 1],
         [0, 1, 2]],

        [[0, 2, 0],
         [0, 2, 1],
         [0, 2, 2]]],


       [[[1, 0, 0],
         [1, 0, 1],
         [1, 0, 2]],

        [[1, 1, 0],
         [1, 1, 1],
         [1, 1, 2]],

        [[1, 2, 0],
         [1, 2, 1],
         [1, 2, 2]]]])

特別な場合には、使用できます

a = numpy.indices((4,)*13)
b = 1j ** numpy.rollaxis(a, 0, 14)

(配列が大きすぎるため、これは 32 ビット システムでは実行されません。テストできるサイズから推定すると、1 分以内に実行されるはずです。)

EIDT: 言及しておくと、 の呼び出しnumpy.rollaxis()は、 と同じ出力を得るために、多かれ少なかれ表面的なものitertools.product()です。インデックスの順序を気にしない場合は、単に省略できます (ただし、配列を連続した配列に変換するフォローアップ操作がない限り、とにかく安価です)。

EDIT2:の正確な類似物を取得するには

numpy.array(list(itertools.product(some_list, repeat=some_length)))

あなたが使用することができます

numpy.array(some_list)[numpy.rollaxis(
    numpy.indices((len(some_list),) * some_length), 0, some_length + 1)
    .reshape(-1, some_length)]

これは完全に読めなくなりました -- これ以上説明する必要があるかどうか教えてください :)

于 2011-01-17T15:29:31.157 に答える
5

リストへの変換をスキップすることで、処理を高速化できます。

numpy.fromiter(c, count=…)  # Using count also speeds things up, but it's optional

この関数を使用すると、最初に NumPy 配列が割り当てられ、次に要素ごとに初期化されます。リスト構築の追加の手順を実行する必要はありません。

PS :fromiter()によって返されたタプルを処理しないproduct()ため、現時点ではこれは解決策ではない可能性があります。fromiter()ただし、が処理された場合dtype=object、これは機能するはずです。

PPS : Joe Kington が指摘したように、これはタプルを構造化配列に入れることで機能させることができます。ただし、これにより常に速度が向上するとは限りません。

于 2011-01-17T13:36:32.680 に答える
5

実際の操作は行われていないため、最初の行一瞬のように見えます。ジェネレーターオブジェクトは、操作が行われているときにそれを反復する場合にのみ構築されます。あなたが言ったように、あなたは4^13 = 67108864数字を取得します。これらはすべて計算され、list通話中に利用可能になります。np.array はリストまたはタプルのみを受け取るので、イテレータからタプルを作成して np.array に渡して、パフォーマンスの違いがあるかどうかを確認し、それがプログラムの全体的なパフォーマンスに影響しないことを確認できます. これはユースケースを試してみるだけで判断できますが、タプルの方がわずかに速いという点もあります。

タプルを試すには、リストの代わりに次のようにします

sendbuf = np.array(tuple(c))
于 2011-01-17T02:37:53.370 に答える
3

numpy.meshgrid にすべての作業を任せます。

length = 13
x = [1, -1, 1j, -1j]
mesh = numpy.meshgrid(*([x] * length))
result = numpy.vstack([y.flat for y in mesh]).T

私のノートブックでは、〜2分かかります

于 2015-12-05T00:00:20.103 に答える
2

まったく異なるアプローチを試してみることをお勧めします。最初に、目的のサイズの空の配列を作成します。

result = np.empty((4**length, length), dtype=complex)

次に、NumPyのスライス機能を使用して、配列に自分で入力します。

# Set up of the last "digit":
result[::4, length-1] = 1
result[1::4, length-1] = -1
result[2::4, length-1] = 1j
result[3::4, length-1] = -1j

他の「数字」(つまり、result [:、2]、result [:、1]、およびresult [:、0]の要素)についても同様のことができます。すべては確かに各桁を繰り返すループに入れることができます。

操作全体(np.empty((length, 4**length)…))を転置すると、(メモリキャッシュをより有効に使用することで)速度が向上する可能性があるため、試す価値があります。

于 2011-01-17T15:43:10.807 に答える
1

おそらく最適化されていませんが、Python 型変換への依存度ははるかに低くなります。

ints = [1,2,3,4]
repeat = 3

def prod(ints, repeat):
    w = repeat
    l = len(ints)
    h = l**repeat
    ints = np.array(ints)
    A = np.empty((h,w), dtype=int)
    rng = np.arange(h)
    for i in range(w):
        x = l**i
        idx = np.mod(rng,l*x)/x
        A[:,i] = ints[idx]
    return A   
于 2011-01-17T06:53:40.367 に答える