以下の、6行4列の行列を2行2列を一塊とするブロック単位でreshapeして12行2列の行列に変換するとする。
z=np.arange(24).reshape(6,4) >z array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]])
その場合、普通にreshapeを使うと以下のように、2行2列のブロックはおかまないなしで変換される。
つまり、最初は[[0,1],[4,5]]というブロックだったのに対し、変換後は[[0,1],[2,3]]となってしまっている。
>np.reshape(z,[12,2]) array([[ 0, 1], [ 2, 3], [ 4, 5], [ 6, 7], [ 8, 9], [10, 11], [12, 13], [14, 15], [16, 17], [18, 19], [20, 21], [22, 23]])
6行4列の行列は、2行2列のブロックが3行2列あるわけなので、expand_dimsを2回作り(1, 1, 6, 4)にした後、
(3, 2, 2, 2)にreshapeする。この最初の(3,2)がブロックの配列で、(2,2)がブロックの大きさに対応している。
> np.expand_dims(np.expand_dims(z,0),0).shape (1, 1, 6, 4) >np.reshape(np.expand_dims(np.expand_dims(z,0),0),[3,2,2,2]).shape (3, 2, 2, 2) >zz = np.reshape(np.expand_dims(np.expand_dims(z,0),0),[3,2,2,2]) >zz array([[[[ 0, 1], [ 2, 3]], [[ 4, 5], [ 6, 7]]], [[[ 8, 9], [10, 11]], [[12, 13], [14, 15]]], [[[16, 17], [18, 19]], [[20, 21], [22, 23]]]])
しかしながら、これも単にreshapeしただけなので、最初のブロックは[[0,1], [4,5]]となってほしいところが[[0,1],[2,3]]になっている。
ここで、[0,1]は4次元配列で言うと、その番地は(0,0,0)に対応し、[2,3]は(0,0,1)、[4,5]は(0,1,0)、[6,7]は(0,1,1)に対応している。
つまり、現在ブロックとしてくっついてしまっている[[0,1],[2,3]]は番地で言うと、(0,0,0)と(0,0,1)に、ブロックでくっつけてほしい[[0,1],[2,3]]は番地で言うと(0,0,0)と(0,0,1)に対応している。つまり、1軸目と2軸目の番地を入れ替えると、[0,1]は(0,0,0)のままであるのに対し、[2,3]は(0,1,0), [4,5]は(0,0,1)となるので、[4,5]は[0,1]とくっつけることができる。
他はどうだろうか?次のブロックは[[2,3],[6,7]]だが、1軸目と2軸目の番地を入れ替えると、[2,3]は(0,1,0)、[6,7]は(0,1,1)となる。したがって、同じブロックとしてくっつけることができている。
したがって、以下のようにtransposeを用いて入れ替えると以下のようになる。
> np.transpose(zz,[0,2,1,3]) array([[[[ 0, 1], [ 4, 5]], [[ 2, 3], [ 6, 7]]], [[[ 8, 9], [12, 13]], [[10, 11], [14, 15]]], [[[16, 17], [20, 21]], [[18, 19], [22, 23]]]]) >np.transpose(zz,[0,2,1,3]).reshape(12,2) array([[ 0, 1], [ 4, 5], [ 2, 3], [ 6, 7], [ 8, 9], [12, 13], [10, 11], [14, 15], [16, 17], [20, 21], [18, 19], [22, 23]])
しかし、この方法では、ブロックが2行2列の場合、元々の行列の列数が4の場合しかうまくいかない。
例えば、以下のように4行6列の場合はうまくいかない。
>z=np.arange(24).reshape(4,6) >z array([[ 0, 1, 2, 3, 4, 5], [ 6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17], [18, 19, 20, 21, 22, 23]]) > zz = np.reshape(np.expand_dims(np.expand_dims(z,0),0),[2,3,2,2]) > zz array([[[[ 0, 1], [ 2, 3]], [[ 4, 5], [ 6, 7]], [[ 8, 9], [10, 11]]], [[[12, 13], [14, 15]], [[16, 17], [18, 19]], [[20, 21], [22, 23]]]]) np.transpose(zz,[0,2,1,3]).reshape(12,2) array([[ 0, 1], [ 4, 5], [ 8, 9], [ 2, 3], [ 6, 7], [10, 11], [12, 13], [16, 17], [20, 21], [14, 15], [18, 19], [22, 23]])
本当は、[[0,1],[6,7]]のブロックを作ってほしいのだが、[[0,1],[4,5]]のブロックになっている。残念。
他によい方法がないだろうか。。。