質問
NumPyで始めたばかりなので、いくつかのコアコンセプトが欠落している可能性があります...
値がリストである辞書からNumPy配列を作成する最良の方法は何ですか?
次のようなもの:
d = { 1: [10,20,30] , 2: [50,60], 3: [100,200,300,400,500] }
次のようになります。
data = [
[10,20,30,?,?],
[50,60,?,?,?],
[100,200,300,400,500]
]
各行で基本的な統計をいくつか行います。例:
deviations = numpy.std(data, axis=1)
質問:
-
ディクショナリからnumpy.arrayを作成する最良/最も効率的な方法は何ですか?辞書は大きいです。数百万個のキーで、それぞれ20個以下のアイテムがあります。
-
各「行」の値の数は異なります。私が正しく理解している場合、numpyは均一なサイズを望んでいるので、std()を幸せにするために不足しているアイテムに何を記入しますか?
更新:言及し忘れたことが1つあります。Pythonの手法は妥当ですが(たとえば、数百万のアイテムのループは高速です)、単一のCPUに制限されています。 Numpy操作はハードウェアにうまく適合し、すべてのCPUにヒットするため、魅力的です。
解決
numpy.std()を呼び出すためにnumpy配列を作成する必要はありません。 辞書のすべての値に対してループでnumpy.std()を呼び出すことができます。リストは、標準のバリエーションを計算するためにその場でnumpy配列に変換されます。
この方法の欠点は、メインループがCではなくpythonにあることです。しかし、これは十分に速いはずです。Cの速度でstdを計算し、多くのメモリを節約できます。可変サイズの配列がある場合、0の値を保存する必要はありません。
- これをさらに最適化する場合は、値をnumpy配列のリストに保存して、pythonリストを作成できます-> numpy配列の変換は1回のみです。
- これでもまだ遅すぎる場合は、psychoを使用してpythonループを最適化してください。
- これでもまだ遅すぎる場合は、numpyモジュールと一緒に Cython を使用してみてください。このチュートリアルでは、画像処理の速度が大幅に向上していると主張しています。または、単にCythonでstd関数全体をプログラムします(sum関数のベンチマークと例については、 this を参照してください)
- Cythonの代わりに SWIG を numpy.i 。
- numpyのみを使用し、すべてをCレベルで計算する場合は、同じサイズのすべてのレコードを異なる配列にグループ化し、それぞれに対してnumpy.std()を呼び出してください。次の例のようになります。
O(N)複雑さの例:
import numpy
list_size_1 = []
list_size_2 = []
for row in data.itervalues():
if len(row) == 1:
list_size_1.append(row)
elif len(row) == 2:
list_size_2.append(row)
list_size_1 = numpy.array(list_size_1)
list_size_2 = numpy.array(list_size_2)
std_1 = numpy.std(list_size_1, axis = 1)
std_2 = numpy.std(list_size_2, axis = 1)
他のヒント
ここにはすでにかなり合理的なアイデアがいくつかありますが、言及する価値があると思います。
欠損値にデフォルト値を入力すると、統計特性(stdなど)が損なわれます。明らかにそれが、Mapadが同じサイズのレコードをグループ化する素晴らしいトリックを提案した理由です。 それに関する問題(レコード長にアプリオリデータがない場合)は、単純なソリューションよりもさらに多くの計算が必要になるということです:
- 少なくとも O(N * logN) 'len'呼び出しと効果的なアルゴリズムを使用した並べ替えの比較
- O(N)はリストを2番目の方法でチェックしてグループ(「垂直」軸の開始インデックスと終了インデックス)を取得します
Psycoを使用するのは良い考えです(驚くほど使いやすいので、ぜひ試してみてください)。
最適な方法は、Mapadの箇条書き#1で説明されている戦略を採用することですが、リスト全体を生成するのではなく、各行をnumpy.arrayに変換し、必要な計算を実行する辞書を反復処理することです。このように:
for row in data.itervalues():
np_row = numpy.array(row)
this_row_std = numpy.std(np_row)
# compute any other statistic descriptors needed and then save to some list
いずれにせよ、Pythonでの数百万のループは、予想されるほど長くはかかりません。それに加えて、これはルーチンの計算のようには見えないので、たまに実行したり、たった一度だけ実行した場合、余分な秒/分かかるかどうかは誰も気にしません。
Mapadによって提案されたものの一般化されたバリアント:
from numpy import array, mean, std
def get_statistical_descriptors(a):
if ax = len(shape(a))-1
functions = [mean, std]
return f(a, axis = ax) for f in functions
def process_long_list_stats(data):
import numpy
groups = {}
for key, row in data.iteritems():
size = len(row)
try:
groups[size].append(key)
except KeyError:
groups[size] = ([key])
results = []
for gr_keys in groups.itervalues():
gr_rows = numpy.array([data[k] for k in gr_keys])
stats = get_statistical_descriptors(gr_rows)
results.extend( zip(gr_keys, zip(*stats)) )
return dict(results)
numpy辞書
構造化配列を使用して、辞書などのキーでnumpyオブジェクトをアドレス指定する機能を保持できます。
import numpy as np
dd = {'a':1,'b':2,'c':3}
dtype = eval('[' + ','.join(["('%s', float)" % key for key in dd.keys()]) + ']')
values = [tuple(dd.values())]
numpy_dict = np.array(values, dtype=dtype)
numpy_dict['c']
現在出力されます
array([ 3.])