3次元以上の多次元配列に対する積がnp.dot()でできるかどうか、試してみよう。
>>> import numpy as np
>>> M234 = np.array(range(1,25)).reshape(2,3,4); M234
array([[[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]],
[[13, 14, 15, 16],
[17, 18, 19, 20],
[21, 22, 23, 24]]])
>>> M43 = np.array(range(1,13)).reshape(4,3); M43
array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]])
>>> np.dot(M234,M43)
array([[[ 70, 80, 90],
[158, 184, 210],
[246, 288, 330]],
[[334, 392, 450],
[422, 496, 570],
[510, 600, 690]]])
(2,3,4)型の配列と(4,3)型の配列の積は、(2,3,3)型の配列になった。
それなら、(2,3,4)型と(4,3,2)型の配列の積は、(2,3,3,2)型になるだろうか。
>>> M432 = np.array(range(1,25)).reshape(4,3,2); M432
array([[[ 1, 2],
[ 3, 4],
[ 5, 6]],
[[ 7, 8],
[ 9, 10],
[11, 12]],
[[13, 14],
[15, 16],
[17, 18]],
[[19, 20],
[21, 22],
[23, 24]]])
>>> np.dot(M234,M432)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<__array_function__ internals>", line 180, in dot
ValueError: shapes (2,3,4) and (4,3,2) not aligned: 4 (dim 2) != 3 (dim 1)
積和を計算するのに、第1配列の第2サイズが4で、第2配列の第1サイズが3で、サイズ違いで計算不可と怒っているようだ。
ということは、第1配列の第2サイズと第2配列の第1サイズが一致すれば計算してくれそうなので試してみよう。
>>> M342 = np.array(range(1,25)).reshape(3,4,2); M342
array([[[ 1, 2],
[ 3, 4],
[ 5, 6],
[ 7, 8]],
[[ 9, 10],
[11, 12],
[13, 14],
[15, 16]],
[[17, 18],
[19, 20],
[21, 22],
[23, 24]]])
>>> np.dot(M234,M342)
array([[[[ 50, 60],
[ 130, 140],
[ 210, 220]],
[[ 114, 140],
[ 322, 348],
[ 530, 556]],
[[ 178, 220],
[ 514, 556],
[ 850, 892]]],
[[[ 242, 300],
[ 706, 764],
[1170, 1228]],
[[ 306, 380],
[ 898, 972],
[1490, 1564]],
[[ 370, 460],
[1090, 1180],
[1810, 1900]]]])
>>> np.shape(np.dot(M234,M342))
(2, 3, 3, 2)
>>>
今度は、第1引数を2次元配列、第2引数を3次元配列にして、np.dot()を行ってみた。
>>> M64 = np.array(range(1,25)).reshape(6,4); M64
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15, 16],
[17, 18, 19, 20],
[21, 22, 23, 24]])
>>> np.dot(M64,M342)
array([[[ 50, 60],
[ 130, 140],
[ 210, 220]],
[[ 114, 140],
[ 322, 348],
[ 530, 556]],
[[ 178, 220],
[ 514, 556],
[ 850, 892]],
[[ 242, 300],
[ 706, 764],
[1170, 1228]],
[[ 306, 380],
[ 898, 972],
[1490, 1564]],
[[ 370, 460],
[1090, 1180],
[1810, 1900]]])
以上から、第1引数配列の最終次元のサイズと、第2引数配列の(最終−1)次元のサイズが一致していれば、多次元配列同士の配列の積が求まるようである。
まず、ベクトルの代わりに、単なるリストを与えてみよう。
>>> np.dot([1,2,3,4],M2345)
array([[[ 110, 120, 130, 140, 150],
[ 310, 320, 330, 340, 350],
[ 510, 520, 530, 540, 550]],
[[ 710, 720, 730, 740, 750],
[ 910, 920, 930, 940, 950],
[1110, 1120, 1130, 1140, 1150]]])
>>> np.dot(M2345,[1,2,3,4,5])
array([[[ 55, 130, 205, 280],
[ 355, 430, 505, 580],
[ 655, 730, 805, 880]],
[[ 955, 1030, 1105, 1180],
[1255, 1330, 1405, 1480],
[1555, 1630, 1705, 1780]]])
np.dot()の第2引数に、リスト、1次元配列、2次元配列を与えてみた。
>>> L5 = [1,2,3,4,5]
>>> M5 = np.array([1,2,3,4,5])
>>> M51 = np.array([1,2,3,4,5]).reshape(5,1)
>>> np.dot(M2345,L5)
array([[[ 55, 130, 205, 280],
[ 355, 430, 505, 580],
[ 655, 730, 805, 880]],
[[ 955, 1030, 1105, 1180],
[1255, 1330, 1405, 1480],
[1555, 1630, 1705, 1780]]])
>>> np.dot(M2345,M5)
array([[[ 55, 130, 205, 280],
[ 355, 430, 505, 580],
[ 655, 730, 805, 880]],
[[ 955, 1030, 1105, 1180],
[1255, 1330, 1405, 1480],
[1555, 1630, 1705, 1780]]])
>>> np.dot(M2345,M51)
array([[[[ 55],
[ 130],
[ 205],
[ 280]],
[[ 355],
[ 430],
[ 505],
[ 580]],
[[ 655],
[ 730],
[ 805],
[ 880]]],
[[[ 955],
[1030],
[1105],
[1180]],
[[1255],
[1330],
[1405],
[1480]],
[[1555],
[1630],
[1705],
[1780]]]])
>>> np.shape(np.dot(M2345,M51))
(2, 3, 4, 1)
nreshape()により、5行1列の配列にした場合、見かけは縦ベクトルに見えるが、しっかり多次元配列同士の積になっていて、結果もちゃんと異なった。
さて、多次元配列の積が行えることが分かった。
しかし、多次元配列ってどういう風に扱えばよいのだろうか。
次回までに考えておこう。