2017-11-28 8 views
0

は、次のプログラムは、配列のネストされたリストから、大きなアレイを作成します。numpyはネストされた配列にどのようにメモリを割り当てますか?

import numpy as np 
a = np.arange(6).reshape(2, 3) 
nested_list = [[a, a + 1], [a + 2, a + 3]] 
b = np.array(nested_list) 

はnp.arrayこの場合、メモリにデータをコピーする前に結果を一度だけのためのメモリを事前に割り当てていますか? 3回にメモリを事前に割り当てるでしょう

c = np.vstack([np.hstack([a, a + 1]), np.hstack([a + 2, a + 3])]) 

それとも、これはに似ていますか?

>>> b 
array([[[[0, 1, 2], 
     [3, 4, 5]], 

     [[1, 2, 3], 
     [4, 5, 6]]], 


     [[[2, 3, 4], 
     [5, 6, 7]], 

     [[3, 4, 5], 
     [6, 7, 8]]]]) 
>>> c 
array([[0, 1, 2, 1, 2, 3], 
     [3, 4, 5, 4, 5, 6], 
     [2, 3, 4, 3, 4, 5], 
     [5, 6, 7, 6, 7, 8]]) 
>>> b.shape 
(2, 2, 2, 3) 
>>> b.reshape(2*2, 2*3) 
array([[0, 1, 2, 3, 4, 5], 
     [1, 2, 3, 4, 5, 6], 
     [2, 3, 4, 5, 6, 7], 
     [3, 4, 5, 6, 7, 8]]) 
+0

hmm ...これらの2つのものが異なります。しかし、私はまだnumpyがbのためにどのようにメモリを割り当てるのか知りたいです。 –

+0

numpyの場合1.13。xでは、numpy.blockを使用することができます。これは、メモリを複数回事前に割り当てているようです。 –

+0

'np.block(nested_list)'は、2次元配列とは異なるものを作成しますが、かなり遅くなります。 – hpaulj

答えて

1

nested_list = [[a, a + 1], [a + 2, a + 3]] 3つの新しいアレイ(合計)に加えて、これらの配列へのポインタのリストを生成します。これは基本的なPythonインタプリタの動作です。

b = np.array(nested_list)np.arrayは複雑なコンパイルされた関数なので、何か深刻な掘り出しがなければ、それが何をするのかを正確に伝えることは難しいです。以前の使用からの印象、特にコンポーネントのサイズが正確に一致しない場合のエラーは、入力をスキャンして作成できる最高次元の配列を決定し、必要に応じて型変換を行います。

時間の比較は簡単です。メモリ使用量を追跡することは困難です。しかし、データコピーが最大の消費者であると仮定すると、時間テストはおそらくメモリ使用の良いプロキシです。そして、私たちがメモリエラーに遭遇していない限り、私たちは通常、メモリ使用よりも時間にもっと関心があります。

In [565]: alist = [[a,a+1],[a+2,a+3]] 
In [566]: allist = [[a.tolist(), (a+1).tolist()],[(a+2).tolist(), (a+3).tolist()]] 

In [567]: timeit np.array(alist) 
6.74 µs ± 63.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 
In [568]: timeit np.array(allist) 
9.92 µs ± 286 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 

ネストされた配列のリストからの作業は、純粋なリストに相当するものよりも少し速くなります。それらの配列をブロックとしてターゲットにコピーしている可能性があります。

個々のスタックは、それはまた、同様にa+nアレイを作成しても、著しく遅い。

In [569]: timeit c = np.vstack([np.hstack([a, a + 1]), np.hstack([a + 2, a + 3])]) 
37.8 µs ± 39 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 

np.stack(デフォルト軸と)np.arrayと全く同じ動作をします。それはあまりにもconcatenateを使用しています。タイミングにa+n計算を含む

In [570]: timeit np.stack(alist) 
28.7 µs ± 262 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 

は、より公正なことがあります

In [571]: %%timeit 
    ...: alist = [[a,a+1],[a+2,a+3]] 
    ...: np.stack(alist) 
    ...: 
38.6 µs ± 509 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 
In [572]: %%timeit 
    ...: alist = [[a,a+1],[a+2,a+3]] 
    ...: np.array(alist) 
    ...: 
15.7 µs ± 177 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 

新しいnp.blockが言及された - それは

かなり遅く違うものを生産しています
In [573]: np.block(alist) 
Out[573]: 
array([[0, 1, 2, 1, 2, 3], 
     [3, 4, 5, 4, 5, 6], 
     [2, 3, 4, 3, 4, 5], 
     [5, 6, 7, 6, 7, 8]]) 
In [574]: timeit np.block(alist) 
126 µs ± 2.39 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) 

block pr

np.vstack([np.hstack([a, a + 1]), np.hstack([a + 2, a + 3])]) 

np.arraynp.stack 4Dアレイを製造:ネストされたスタックと同様の2Dアレイをoduces。 2dに再構成できますが、要素の順序は異なります。一致させるには、再構成する前にトランスポーズを行う必要があります。例えば

In [590]: np.array(alist).transpose(0,2,1,3).reshape(4,6) 
Out[590]: 
array([[0, 1, 2, 1, 2, 3], 
     [3, 4, 5, 4, 5, 6], 
     [2, 3, 4, 3, 4, 5], 
     [5, 6, 7, 6, 7, 8]]) 
+0

np.blockがhstack + vstackの組み合わせより約3倍遅いことは驚くべきことです。私はそれがそのようになるとは決して考えなかった。 –

+0

1.14 [速い](https://github.com/numpy/numpy/pull/9667) 'np.block'の実装は、コストを約1.7倍遅くします(' np.vstack([ np.hstack(alist [0])、np.hstack(alist [1])]))。連結を使用すると、 'hstack'と' vstack'に比べて2.5倍の高速化が可能です。小さな配列の場合、Python関数を実行するコストが支配的です – Eric

関連する問題