web-dev-qa-db-ja.com

連続配列と非連続配列の違いは何ですか?

numpy manual reshape()関数については、

_>>> a = np.zeros((10, 2))
# A transpose make the array non-contiguous
>>> b = a.T
# Taking a view makes it possible to modify the shape without modifying the
# initial object.
>>> c = b.view()
>>> c.shape = (20)
AttributeError: incompatible shape for a non-contiguous array
_

私の質問は:

  1. 連続配列および非連続配列とは何ですか? 連続メモリブロックとは何ですか? のようなCの連続メモリブロックに似ていますか?
  2. これら2つの間にパフォーマンスの違いはありますか?いつどちらを使用する必要がありますか?
  3. 転置により配列が不連続になるのはなぜですか?
  4. c.shape = (20)がエラー_incompatible shape for a non-contiguous array_をスローするのはなぜですか?

ご回答有難うございます!

66
jdeng

12の異なる配列値を使用したこの例が役立つ場合があります。

In [207]: x=np.arange(12).reshape(3,4).copy()

In [208]: x.flags
Out[208]: 
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  ...
In [209]: x.T.flags
Out[209]: 
  C_CONTIGUOUS : False
  F_CONTIGUOUS : True
  OWNDATA : False
  ...

C order値は、生成された順序です。転置された値は、

In [212]: x.reshape(12,)   # same as x.ravel()
Out[212]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

In [213]: x.T.reshape(12,)
Out[213]: array([ 0,  4,  8,  1,  5,  9,  2,  6, 10,  3,  7, 11])

両方の1Dビューを取得できます

In [214]: x1=x.T

In [217]: x.shape=(12,)

xの形状も変更できます。

In [220]: x1.shape=(12,)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-220-cf2b1a308253> in <module>()
----> 1 x1.shape=(12,)

AttributeError: incompatible shape for a non-contiguous array

ただし、トランスポーズの形状は変更できません。 dataはまだ0,1,2,3,4...の順序にあり、1d配列で0,4,8...としてアクセスすることはできません。

ただし、x1のコピーは変更できます。

In [227]: x2=x1.copy()

In [228]: x2.flags
Out[228]: 
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  ...
In [229]: x2.shape=(12,)

stridesを調べることも役立ちます。歩幅は、次の値に到達するためにどれだけ(バイト単位で)歩かなければならないかです。 2D配列の場合、2つのストライド値があります。

In [233]: x=np.arange(12).reshape(3,4).copy()

In [234]: x.strides
Out[234]: (16, 4)

次の行に移動するには、16バイト、次の列のみをステップ4します。

In [235]: x1.strides
Out[235]: (4, 16)

転置は、ストライドの順序を切り替えるだけです。次の行は4バイトのみ、つまり次の数字です。

In [236]: x.shape=(12,)

In [237]: x.strides
Out[237]: (4,)

形状を変更すると、ストライドも変更されます-一度に4バイトずつバッファをステップスルーします。

In [238]: x2=x1.copy()

In [239]: x2.strides
Out[239]: (12, 4)

x2x1に似ていますが、独自のデータバッファーがあり、値の順序は異なります。次の列は4バイトオーバーになり、次の行は12(3 * 4)になります。

In [240]: x2.shape=(12,)

In [241]: x2.strides
Out[241]: (4,)

xと同様に、形状を1dに変更すると、歩幅が(4,)に減少します。

x1の場合、0,1,2,...順序のデータでは、0,4,8...を与える1Dストライドはありません。

__array_interface__は、配列情報を表示するもう1つの便利な方法です。

In [242]: x1.__array_interface__
Out[242]: 
{'strides': (4, 16),
 'typestr': '<i4',
 'shape': (4, 3),
 'version': 3,
 'data': (163336056, False),
 'descr': [('', '<i4')]}

x1データバッファアドレスは、データを共有するxと同じです。 x2には異なるバッファアドレスがあります。

copyおよびreshapeコマンドにorder='F'パラメーターを追加して実験することもできます。

7
hpaulj