web-dev-qa-db-ja.com

Numpyで配列をその場で拡張する方法は?

現在、私はこのようなコードをいくつか持っています

import numpy as np
ret = np.array([])
for i in range(100000):
  tmp =  get_input(i)
  ret = np.append(ret, np.zeros(len(tmp)))
  ret = np.append(ret, np.ones(fixed_length))

このコードは非効率的 as np.appendは、retをインプレースで変更の代わりに配列のコピーを返す必要があります

私はこのようなnumpy配列にextendを使用できるかどうか疑問に思っていました:

import numpy as np
from somewhere import np_extend
ret = np.array([])
for i in range(100000):
  tmp =  get_input(i)
  np_extend(ret, np.zeros(len(tmp)))
  np_extend(ret, np.ones(fixed_length))

extendの方がはるかに効率的です。これについてのアイデアはありますか?ありがとう!

26
Hanfei Sun

Numpy配列がメモリの1つの連続したブロックを占有していると想像してください。ここで、numpy配列の左右のメモリを占有している他のオブジェクト、たとえばnumpy配列を想像してください。 numpy配列に追加または拡張する余地はありません。 numpy配列の基になるデータは、常に連続メモリブロックを占有します。

したがって、numpy配列に追加または拡張する要求は、メモリの新しい大きなブロック全体を割り当て、古いデータを新しいブロックにコピーしてから追加または拡張することによってのみ満たすことができます。

そう:

  1. インプレースでは発生しません。
  2. 効率的ではありません。
32
unutbu

Ndarraysの.resize()メソッドを使用できます。メモリが他の配列/変数によって参照されないことが必要です。

import numpy as np
ret = np.array([])
for i in range(100):
    tmp = np.random.Rand(np.random.randint(1, 100))
    ret.resize(len(ret) + len(tmp)) # <- ret is not referred to by anything else,
                                    #    so this works
    ret[-len(tmp):] = tmp

効率は、通常のアレイメモリの過剰割り当て方式を使用することで改善できます。

12
pv.

これを処理する通常の方法は次のようなものです。

import numpy as np
ret = []
for i in range(100000):
  tmp =  get_input(i)
  ret.append(np.zeros(len(tmp)))
  ret.append(np.zeros(fixed_length))
ret = np.concatenate(ret)

他の答えが入った理由により、データをコピーせずにアレイを拡張することは一般的に不可能です。

10
Bi Rico

インプレースnumpy挿入方法を調査するこの質問に出会いました。

ここで与えられた答えを読んでいると、私には別の選択肢がありました(おそらく素朴なものですが、まだアイデアです):numpy配列をリストに戻し、追加したいものを追加して再変換しないのはなぜですか?配列に戻る?

多数の挿入を行う必要がある場合は、すべての挿入を一度にリストに挿入する一種の「リストキャッシュ」を作成できます。

もちろん、リストへの変換とnumpyへの変換を一切回避しようとする場合、これはオプションではありません。

0