193

ジェネレーターオブジェクトからnumpy配列を構築するにはどうすればよいですか?

問題を説明しましょう:

>>> import numpy
>>> def gimme():
...   for x in xrange(10):
...     yield x
...
>>> gimme()
<generator object at 0x28a1758>
>>> list(gimme())
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> numpy.array(xrange(10))
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> numpy.array(gimme())
array(<generator object at 0x28a1758>, dtype=object)
>>> numpy.array(list(gimme()))
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

この例でgimme()は、出力を配列に変換したいジェネレーターです。ただし、配列コンストラクターはジェネレーターを反復処理せず、ジェネレーター自体を格納するだけです。私が望む動作は からnumpy.array(list(gimme()))のものですが、中間リストと最終配列を同時にメモリに持つことによるメモリオーバーヘッドを払いたくありません。よりスペース効率の良い方法はありますか?

4

5 に答える 5

232

One google behind this stackoverflow result, I found that there is a numpy.fromiter(data, dtype, count). The default count=-1 takes all elements from the iterable. It requires a dtype to be set explicitly. In my case, this worked:

numpy.fromiter(something.generate(from_this_input), float)

于 2009-02-24T03:53:18.183 に答える
147

Numpy配列では、Pythonリストとは異なり、作成時に長さを明示的に設定する必要があります。これは、各アイテムのスペースをメモリに連続して割り当てることができるようにするために必要です。連続した割り当ては、numpy配列の重要な機能です。これをネイティブコードの実装と組み合わせると、通常のリストよりもはるかに高速に操作を実行できます。

これを念頭に置いて、次のいずれかを行わない限り、ジェネレータオブジェクトを取得して配列に変換することは技術的に不可能です。

  1. 実行時に生成される要素の数を予測できます。

    my_array = numpy.empty(predict_length())
    for i, el in enumerate(gimme()): my_array[i] = el
    
  2. その要素を中間リストに保存する用意があります:

    my_array = numpy.array(list(gimme()))
    
  3. 2つの同一のジェネレーターを作成し、最初のジェネレーターを実行して全長を見つけ、配列を初期化してから、ジェネレーターを再度実行して各要素を見つけることができます。

    length = sum(1 for el in gimme())
    my_array = numpy.empty(length)
    for i, el in enumerate(gimme()): my_array[i] = el
    

1はおそらくあなたが探しているものです。2はスペース効率が悪く、3は時間効率が悪い(ジェネレーターを2回通過する必要があります)。

于 2008-12-15T06:31:12.347 に答える
6

やや接線的ですが、ジェネレーターがリスト内包表記の場合、 を使用numpy.whereして結果をより効果的に取得できます (この投稿を見た後、自分のコードでこれを発見しました)

于 2009-05-12T20:33:33.277 に答える