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)