42

ループで 1 次元の numpy 配列のリストを生成し、後でこのリストを 2d numpy 配列に変換します。アイテムの数を事前に知っていれば、2次元のnumpy配列を事前に割り当てていましたが、そうではないため、すべてをリストに入れました。

モックアップは以下です。

>>> list_of_arrays = map(lambda x: x*ones(2), range(5))
>>> list_of_arrays
[array([ 0.,  0.]), array([ 1.,  1.]), array([ 2.,  2.]), array([ 3.,  3.]), array([ 4.,  4.])]
>>> arr = array(list_of_arrays)
>>> arr
array([[ 0.,  0.],
       [ 1.,  1.],
       [ 2.,  2.],
       [ 3.,  3.],
       [ 4.,  4.]])

私の質問は次のとおりです。

それらをリストに入れてからnumpy.arrayを作成するよりも、連続した数値データ(私の場合はnumpy配列)を収集するタスクについて(パフォーマンス的に)より良い方法はありますか(私は新しいobjを作成してコピーしていますデータ)?十分にテストされたモジュールで利用可能な「拡張可能な」マトリックスデータ構造はありますか?

私の 2D マトリックスの典型的なサイズは、100x10 から 5000x10 の浮動小数点数です。

編集:この例ではマップを使用していますが、実際のアプリケーションでは for ループがあります

4

6 に答える 6

22

を使用した便利な方法numpy.concatenate。@unutbuの答えよりも速いと思います:

In [32]: import numpy as np 

In [33]: list_of_arrays = list(map(lambda x: x * np.ones(2), range(5)))

In [34]: list_of_arrays
Out[34]: 
[array([ 0.,  0.]),
 array([ 1.,  1.]),
 array([ 2.,  2.]),
 array([ 3.,  3.]),
 array([ 4.,  4.])]

In [37]: shape = list(list_of_arrays[0].shape)

In [38]: shape
Out[38]: [2]

In [39]: shape[:0] = [len(list_of_arrays)]

In [40]: shape
Out[40]: [5, 2]

In [41]: arr = np.concatenate(list_of_arrays).reshape(shape)

In [42]: arr
Out[42]: 
array([[ 0.,  0.],
       [ 1.,  1.],
       [ 2.,  2.],
       [ 3.,  3.],
       [ 4.,  4.]])
于 2016-01-16T18:49:43.000 に答える
21

arr最終的な配列が5000x10より大きくなることは決してないことを知っていると仮定します。次に、最大サイズの配列を事前に割り当て、ループを通過するときにデータを入力し、ループarr.resizeを終了した後に検出されたサイズに縮小するために使用できます。

以下のテストは、配列の最終的なサイズに関係なく、中間のpythonリストを作成するよりもわずかに高速になることを示しています。

また、arr.resize未使用のメモリの割り当てを解除するため、最終的な(中間ではないかもしれませんが)メモリフットプリントは、によって使用されるものよりも小さくなりpython_lists_to_arrayます。

これnumpy_all_the_wayはより速いショーです:

% python -mtimeit -s"import test" "test.numpy_all_the_way(100)"
100 loops, best of 3: 1.78 msec per loop
% python -mtimeit -s"import test" "test.numpy_all_the_way(1000)"
100 loops, best of 3: 18.1 msec per loop
% python -mtimeit -s"import test" "test.numpy_all_the_way(5000)"
10 loops, best of 3: 90.4 msec per loop

% python -mtimeit -s"import test" "test.python_lists_to_array(100)"
1000 loops, best of 3: 1.97 msec per loop
% python -mtimeit -s"import test" "test.python_lists_to_array(1000)"
10 loops, best of 3: 20.3 msec per loop
% python -mtimeit -s"import test" "test.python_lists_to_array(5000)"
10 loops, best of 3: 101 msec per loop

これはnumpy_all_the_way、使用するメモリが少ないことを示しています。

% test.py
Initial memory usage: 19788
After python_lists_to_array: 20976
After numpy_all_the_way: 20348

test.py:

import numpy as np
import os


def memory_usage():
    pid = os.getpid()
    return next(line for line in open('/proc/%s/status' % pid).read().splitlines()
                if line.startswith('VmSize')).split()[-2]

N, M = 5000, 10


def python_lists_to_array(k):
    list_of_arrays = list(map(lambda x: x * np.ones(M), range(k)))
    arr = np.array(list_of_arrays)
    return arr


def numpy_all_the_way(k):
    arr = np.empty((N, M))
    for x in range(k):
        arr[x] = x * np.ones(M)
    arr.resize((k, M))
    return arr

if __name__ == '__main__':
    print('Initial memory usage: %s' % memory_usage())
    arr = python_lists_to_array(5000)
    print('After python_lists_to_array: %s' % memory_usage())
    arr = numpy_all_the_way(5000)
    print('After numpy_all_the_way: %s' % memory_usage())
于 2010-01-21T03:09:39.237 に答える
16

@Gill Batesの回答よりもさらに簡単な、1行のコードを次に示します。

np.stack(list_of_arrays, axis=0)
于 2018-03-06T01:34:39.873 に答える
2

あなたがしていることは標準的な方法です。numpy 配列のプロパティは、連続したメモリを必要とすることです。私が考えることができる「穴」の唯一の可能性は のstridesメンバーで可能ですPyArrayObjectが、それはここでの議論には影響しません. numpy 配列には連続したメモリがあり、「事前に割り当てられている」ため、新しい行/列を追加すると、新しいメモリが割り当てられ、データがコピーされ、古いメモリが解放されます。それをたくさんやると効率が悪いです。

リストを作成して、最後にそれを numpy 配列に変換したくないケースの 1 つは、リストに多数の数値が含まれている場合です。数値の numpy 配列は、Python のネイティブの数値リストよりもはるかに少ないスペースしか必要としません (ネイティブの Python リストには Python オブジェクトが格納されます)。あなたの典型的な配列サイズでは、それは問題ではないと思います。

配列のリストから最終的な配列を作成すると、すべてのデータが新しい (例では 2 次元) 配列の新しい場所にコピーされますnext = numpy.vstack((next, new_row))これは、numpy 配列を使用して新しいデータを取得するたび に行うよりもはるかに効率的です。vstack()すべての「行」のすべてのデータをコピーします。

少し前に numpy-discussion メーリング リストに、効率的な拡張/追加を可能にする新しい numpy 配列型を追加する可能性について議論したスレッドがありました。当時、これにはかなりの関心があったようですが、そこから何かが生まれたかどうかはわかりません. あなたはそのスレッドを見たいと思うかもしれません。

あなたがしていることは非常に Pythonic で効率的だと思います。そのため、何か他のこと (より多くのスペース効率など) が本当に必要でない限り、問題ないはずです。これは、最初に配列内の要素の数がわからない場合に、numpy 配列を作成する方法です。

于 2010-01-21T01:38:00.567 に答える
2

〜unutbuの回答の独自のバージョンを追加します。numpy_all_the の方法と似ていますが、インデックス エラーがある場合は動的にサイズを変更します。小さなデータセットの場合は少し速いと思っていましたが、少し遅いです.境界チェックは物事を遅くしすぎます.

initial_guess = 1000

def my_numpy_all_the_way(k):
    arr=np.empty((initial_guess,M))
    for x,row in enumerate(make_test_data(k)):
        try:
            arr[x]=row
        except IndexError:
            arr.resize((arr.shape[0]*2, arr.shape[1]))
            arr[x]=row
    arr.resize((k,M))
    return arr
于 2010-01-21T06:58:28.940 に答える
2

さらに簡単な@fnjnの答え

np.vstack(list_of_arrays)
于 2018-10-19T12:56:50.223 に答える