numpy.array形状(R、1)と(R、)の違い


320

ではnumpy、一部の操作は正常に(R, 1)戻り(R,)ますが、一部は戻ります。これは明示的でreshapeある必要があるため、行列の乗算をより退屈なものにします。たとえば、行列が与えられた場合M、行数をnumpy.dot(M[:,0], numpy.ones((1, R)))どこにしたいのかR(もちろん、同じ問題が列ごとにも発生します)。当社は、取得しますmatrices are not alignedので、エラーをM[:,0]形状である(R,)が、numpy.ones((1, R))形状です(1, R)

だから私の質問は:

  1. 形状(R, 1)との違いは何ですか(R,)。文字通り、数字のリストとリストのリストで、すべてのリストに数字だけが含まれていることがわかります。行列の乗算を簡単にするのではなく、numpy形状(R, 1)を優先するように設計しないのはなぜでしょうか(R,)

  2. 上記の例にもっと良い方法はありますか?このように明示的に再形成しない場合:numpy.dot(M[:,0].reshape(R, 1), numpy.ones((1, R)))


3
これは役立つかもしれません。しかし、実用的な解決策を見つけることではありません。
キーヤー

1
適切なソリューション:numpy.ravel(M [:、0])-形状を(R、1)から(R、)に変換します
Andi R

回答:


545

1. NumPyでの形状の意味

あなたは「文字通り数字のリストと、すべてのリストに数字だけが含まれているリストのリストだと知っている」と書いていますが、それはそれについて考えるのに少し役に立たない方法です。

numpyのアレイを考えるための最良の方法は、彼らは2つの部分から成っていることであるデータバッファ単なる生の要素のブロック、及びあるビューデータバッファを解釈する方法について説明します。

たとえば、12個の整数の配列を作成すると、次のようになります。

>>> a = numpy.arange(12)
>>> a
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

次にa、次のように配置されたデータバッファで構成されます。

┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
  0   1   2   3   4   5   6   7   8   9  10  11 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

データの解釈方法を説明するビュー:

>>> a.flags
  C_CONTIGUOUS : True
  F_CONTIGUOUS : True
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False
>>> a.dtype
dtype('int64')
>>> a.itemsize
8
>>> a.strides
(8,)
>>> a.shape
(12,)

ここでの形状と (12,)は、0から11までの単一のインデックスによって配列がインデックス付けされることを意味します。概念的には、この単一のインデックスiにラベルを付けると、配列aは次のようになります。

i= 0    1    2    3    4    5    6    7    8    9   10   11
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
  0   1   2   3   4   5   6   7   8   9  10  11 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

我々は場合再構築配列を、これはデータバッファは変更されません。代わりに、データを解釈する別の方法を説明する新しいビューを作成します。だから後:

>>> b = a.reshape((3, 4))

配列bはと同じデータバッファーを持っていますaが、現在はそれぞれ0から2および0から3で実行される2つのインデックスによってインデックスが付けられています。2つのインデックスiとにラベルを付けるとj、配列bは次のようになります。

i= 0    0    0    0    1    1    1    1    2    2    2    2
j= 0    1    2    3    0    1    2    3    0    1    2    3
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
  0   1   2   3   4   5   6   7   8   9  10  11 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

つまり:

>>> b[2,1]
9

2番目のインデックスの変化が速く、最初のインデックスの変化が遅いことがわかります。これを逆にしたい場合は、orderパラメーターを指定できます。

>>> c = a.reshape((3, 4), order='F')

その結果、次のようにインデックスが付けられた配列になります。

i= 0    1    2    0    1    2    0    1    2    0    1    2
j= 0    0    0    1    1    1    2    2    2    3    3    3
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
  0   1   2   3   4   5   6   7   8   9  10  11 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

つまり:

>>> c[2,1]
5

これで、配列がサイズ1の1つ以上の次元を持つ形状を持つことの意味が明確になります。後:

>>> d = a.reshape((12, 1))

配列にdは2つのインデックスでインデックスが付けられ、最初のインデックスは0〜11で、2番目のインデックスは常に0です。

i= 0    1    2    3    4    5    6    7    8    9   10   11
j= 0    0    0    0    0    0    0    0    0    0    0    0
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
  0   1   2   3   4   5   6   7   8   9  10  11 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

など:

>>> d[10,0]
10

長さ1の次元は「自由」(ある意味で)なので、町に行くのを妨げるものは何もありません。

>>> e = a.reshape((1, 2, 1, 6, 1))

このようにインデックス付けされた配列を与える:

i= 0    0    0    0    0    0    0    0    0    0    0    0
j= 0    0    0    0    0    0    1    1    1    1    1    1
k= 0    0    0    0    0    0    0    0    0    0    0    0
l= 0    1    2    3    4    5    0    1    2    3    4    5
m= 0    0    0    0    0    0    0    0    0    0    0    0
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
  0   1   2   3   4   5   6   7   8   9  10  11 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

など:

>>> e[0,1,0,0,0]
6

配列の実装方法の詳細については、NumPy内部ドキュメントを参照してください。

2.何をすべきか?

以来 numpy.reshape新しいビューを作成するだけな、必要なときにいつでもそれを使用することを恐れる必要はありません。これは、別の方法で配列にインデックスを付ける場合に使用する適切なツールです。

ただし、長い計算では、最初に「正しい」形状の配列を構築するように配置することが通常可能です。そのため、形状変更と転置の数を最小限に抑えます。しかし、再形成の必要性につながった実際のコンテキストを見なければ、何を変更すべきかを言うのは難しいです。

あなたの質問の例は:

numpy.dot(M[:,0], numpy.ones((1, R)))

しかし、これは現実的ではありません。まず、この式:

M[:,0].sum()

結果をより簡単に計算します。第二に、列0について本当に特別なことはありますか?おそらく、実際に必要なものは次のとおりです。

M.sum(axis=0)

34
これは、配列の格納方法を考える上で非常に役立ちました。ありがとうございました!さらに行列計算を行うために(2次元)行列の列(または行)にアクセスすることは、列を適切に再形成する必要があるため、不便です。形状を(n、)から(n、1)に変更する必要があります。
OfLettersAndNumbers 2016年

3
@SammyLee:使用newaxisあなたは別の軸が必要な場合、例えばa[:, j, np.newaxis]あるjの番目の列a、およびa[np.newaxis, i]あるi行目。
Gareth Rees

私はこのモデルによって紙でより良い理解を得るためにインデックスをプロットしようとしています、そして私が2 x 2 x 4の形状を持っていた場合、最初の2は0000000011111111として理解でき、最後の4は0123012301230123として理解されます
PirateApp 2018

3
これを考える簡単な方法は、numpyが期待どおりに機能していることですが、Pythonによるタプルの出力は誤解を招く可能性があります。この(R, )場合、の形状はndarray単一の要素を持つタプルなので、末尾のコンマを付けてPythonによって出力されます。余分なコンマがないと、括弧内の式あいまいになりますndarray単一寸法の長さの列ベクトルとしてのもであってもよいですR。で(R, 1)場合、タプルは2つの要素を持っているので、行ベクトル(又は長さの1列を持つ行列と考えることができるR
マイケル・ヤン

1
@ Alex-droidAD:この質問とその回答をご覧ください。
Gareth Rees、

16

との違いは(R,)(1,R)文字通り、使用する必要があるインデックスの数です。 ones((1,R))たまたま行が1つしかない2次元配列です。 ones(R)ベクトルです。一般に、変数が複数の行/列を持つことが意味をなさない場合は、単一の次元を持つ行列ではなく、ベクトルを使用する必要があります。

特定のケースでは、いくつかのオプションがあります。

1)2番目の引数をベクトルにします。以下は正常に動作します:

    np.dot(M[:,0], np.ones(R))

2)matlabのような行列演算が必要な場合は、のmatrix代わりにクラスを使用しndarrayます。すべての行列は強制的に2次元配列になり、演算子*は要素ごとではなく行列の乗算を行います(そのため、ドットは必要ありません)。私の経験では、これはそれだけの価値がある問題ですが、Matlabに慣れている場合は良いかもしれません。


はい。よりMATLABのような動作を期待していました。matrixクラスを見てみましょう。matrixところで、クラスBTW の問題は何ですか?
clwen 2014

2
の問題matrixは、それが2Dのみであること、および演算子 '*'をオーバーロードするためndarray、で使用した場合に作成された関数が失敗する可能性があることですmatrix
エヴァン

11

形状はタプルです。次元が1つしかない場合、形状は1つの数値になり、カンマの後は空白になります。2次元以上の場合、すべてのコンマの後に数字が表示されます。

# 1 dimension with 2 elements, shape = (2,). 
# Note there's nothing after the comma.
z=np.array([  # start dimension
    10,       # not a dimension
    20        # not a dimension
])            # end dimension
print(z.shape)

(2)

# 2 dimensions, each with 1 element, shape = (2,1)
w=np.array([  # start outer dimension 
    [10],     # element is in an inner dimension
    [20]      # element is in an inner dimension
])            # end outer dimension
print(w.shape)

(2,1)


5

その基本配列クラスの場合、2D配列は1Dまたは3D配列にすぎません。寸法を保存する操作、縮小する操作、結合または拡大する操作があります。

M=np.arange(9).reshape(3,3)
M[:,0].shape # (3,) selects one column, returns a 1d array
M[0,:].shape # same, one row, 1d array
M[:,[0]].shape # (3,1), index with a list (or array), returns 2d
M[:,[0,1]].shape # (3,2)

In [20]: np.dot(M[:,0].reshape(3,1),np.ones((1,3)))

Out[20]: 
array([[ 0.,  0.,  0.],
       [ 3.,  3.,  3.],
       [ 6.,  6.,  6.]])

In [21]: np.dot(M[:,[0]],np.ones((1,3)))
Out[21]: 
array([[ 0.,  0.,  0.],
       [ 3.,  3.,  3.],
       [ 6.,  6.,  6.]])

同じ配列を与える他の式

np.dot(M[:,0][:,np.newaxis],np.ones((1,3)))
np.dot(np.atleast_2d(M[:,0]).T,np.ones((1,3)))
np.einsum('i,j',M[:,0],np.ones((3)))
M1=M[:,0]; R=np.ones((3)); np.dot(M1[:,None], R[None,:])

MATLABは、2D配列から始めました。新しいバージョンでは、より多くの次元を使用できますが、2の下限が維持されます。しかし、形状(1,3)vの行行列と列1の違いに注意を払う必要があります(3,1)。どのくらいの頻度で書きました[1,2,3].'か?私はrow vectorand を書くつもりでしたcolumn vectorが、その2d制約により、MATLABにはベクトルがありません-少なくとも1dとしてのベクトルの数学的な意味では。

あなたが見てきましたnp.atleast_2d(また_1dと_3Dのバージョン)?


1

1)(R, 1)以上の形状を好まない理由(R,)は、それが不必要に物事を複雑にするためです。その上、なぜ(R, 1)長さRのベクトルの代わりにデフォルトで形状を持つのが望ましいの(1, R)でしょうか?追加のディメンションが必要な場合は、シンプルにして明示的にすることをお勧めします。

2)たとえば、外積を計算しているので、次のreshapeコマンドを使用して、呼び出しなしでこれを実行できますnp.outer

np.outer(M[:,0], numpy.ones((1, R)))

答えてくれてありがとう。1)M[:,0]は基本的に最初の要素を持つすべての行を取得するので、を持つ(R, 1)よりも意味があり(1, R)ます。2)それはnp.outer、例えば、形(1、R)の後に(R、1)のマトリックスのドットのように、常に置き換え可能ではありません。
clwen 2014

1)はい、それは慣例かもしれませんが、それは他の状況ではあまり便利ではありません。M [1、1]が形状(1、1)配列を返すようにすることもできますが、通常はスカラーよりも便利ではありません。マトリックスのような動作が本当に必要な場合は、matrixオブジェクトを使用した方がよいでしょう。2)実際にnp.outer(1, R)、形状が、、(R, 1)またはその2つの組み合わせであるかどうかに関係なく機能します。
bogatron 2014

0

ここにはすでに良い答えがたくさんあります。しかし、私にとって、形状や配列がすべてのプログラムを壊す可能性がある例を見つけるのは困難でした。

だからここにある:

import numpy as np
a = np.array([1,2,3,4])
b = np.array([10,20,30,40])


from sklearn.linear_model import LinearRegression
regr = LinearRegression()
regr.fit(a,b)

これはエラーで失敗します:

ValueError:期待される2D配列、代わりに1D配列を得ました

しかし、以下に追加するreshapea

a = np.array([1,2,3,4]).reshape(-1,1)

これは正しく動作します!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.