他の多くの人と同じように、私の状況では、大量のデータを収集し、データをnumpy配列として返すメソッドを提供するクラスがあります。(配列を返した後でも、追加のデータが流入し続ける可能性があります)。配列の作成はコストのかかる操作であるため、必要な場合にのみ作成し、可能な限り効率的に(具体的には、可能な場合はデータをインプレースで追加するために)作成したいと思います。
そのために、私はndarray.resize()メソッドとrefcheck引数について読んでいます。「この配列のメモリを別のPythonオブジェクトと共有していないことが確実な場合」にのみ、refcheckをFalseに設定する必要があることを理解しています。
よくわかりません。持っていることもあれば、持っていないこともあります。refcehckが失敗した場合にエラーが発生しても問題ありませんが(キャッチして新しいコピーを作成できます)、安全であることがわかっているものを無視して、「実際の」外部参照がある場合にのみ失敗させたいと思います。
簡略化した図を次に示します。
import numpy as np
def array_append(arr, values, refcheck = True):
added_len = len(values)
if added_len == 0:
return arr
old_len = len(arr)
new_len = old_len + added_len
arr.resize(new_len, refcheck = refcheck)
arr[old_len:] = values
return arr
class DataCollector(object):
def __init__(self):
self._new_data = []
self._arr = np.array([])
def add_data(self, data):
self._new_data.append(data)
def get_data_as_array(self):
self._flush()
return self._arr
def _flush(self):
if not self._new_data:
return
# self._arr = self._append1()
# self._arr = self._append2()
self._arr = self._append3()
self._new_data = []
def _append1(self):
# always raises an error, because there are at least 2 refs:
# self._arr and local variable 'arr' in array_append()
return array_append(self._arr, self._new_data, refcheck = True)
def _append2(self):
# Does not raise an error, but unsafe in case there are other
# references to self._arr
return array_append(self._arr, self._new_data, refcheck = False)
def _append3(self):
# "inline" version: works if there are no other references
# to self._arr, but raises an error if there are.
added_len = len(self._new_data)
old_len = len(self._arr)
self._arr.resize(old_len + added_len, refcheck = True)
self._arr[old_len:] = self._new_data
return self._arr
dc = DataCollector()
dc.add_data(0)
dc.add_data(1)
print dc.get_data_as_array()
dc.add_data(2)
print dc.get_data_as_array()
x = dc.get_data_as_array() # create an external reference
print x.shape
for i in xrange(5000):
dc.add_data(999)
print dc.get_data_as_array()
print x.shape
質問:
- 私がやろうとしていること(numpy配列を段階的に作成する)を行うためのより良い(高速な)方法はありますか?
- resize()メソッドに「refcheckを実行しますが、安全であることがわかっている1つの参照(またはn個の参照)を無視する」ように指示する方法はありますか?(これにより、_append1()が常に失敗するという問題が解決されます)