質問

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が同じサイズのレコードをグループ化する素晴らしいトリックを提案した理由です。 それに関する問題(レコード長にアプリオリデータがない場合)は、単純なソリューションよりもさらに多くの計算が必要になるということです:

  1. 少なくとも O(N * logN) 'len'呼び出しと効果的なアルゴリズムを使用した並べ替えの比較
  2. 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.])
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top