web-dev-qa-db-ja.com

numpy配列のリストからnumpy配列を作成するPythonの方法

ループ内で1次元のnumpy配列のリストを生成し、後でこのリストを2次元のnumpy配列に変換します。前もってアイテムの数を知っていれば、2D 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フロートです

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

40

最終的な配列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 __== '__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())
18
unutbu

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.]])
19
Gill Bates

@Gill Batesの答えよりもさらに簡単なのが、1行のコードです。

np.stack(list_of_arrays, axis=0)
13
fnjn

独自のバージョンの〜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
2
wisty

さらに簡単な@fnjnの答え

np.vstack(list_of_arrays)

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

誰かがリストを作成して、最後にnumpy配列に変換したくない場合の1つは、リストに多くの数字が含まれている場合です:numpyの数字配列は、ネイティブPython数字のリスト(ネイティブPythonリストストアPythonオブジェクト)から。典型的な配列サイズについては、問題。

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

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

私はあなたがやっていることは非常にPython的で効率的であると言いますので、本当に何か他のものが必要でない限り(おそらくスペース効率が高いでしょうか?)、あなたは大丈夫です。これは、最初に配列内の要素の数がわからないときにnumpy配列を作成する方法です。

2
Alok Singhal