numpy.tile()で列ベクトルを繰り返したいのに失敗する

行列から一列を抽出して繰り返そうとするとエラーが出てしまった

下の例は、行列Aの1列目 (0-index) を行方向に3回繰り返した2×3行列を作って、別の2×3行列Bに足そうと試みている

>>> A
array([[0., 1., 0.],
       [1., 0., 0.]])
>>> B
array([[0., 0., 2.],
       [0., 1., 0.]])
>>> B + np.tile(A[:, 1], (1, 3))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (2,3) (1,6) 

脳死の解決策

行列Bは2×3なのに、np.tile(A[:, 1], (1, 3))は1×6になっている

脳死で転置してみても変わらない

>>> B + np.tile(A[:, 1].T, (1, 3))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (2,3) (1,6) 

第2引数の指定を逆にしてみたら転置した状態になった

>>> B + np.tile(A[:, 1], (3, 1))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (2,3) (3,2) 

だったら結果を転置してしまえ!!!!

>>> B + np.tile(A[:, 1], (3, 1)).T
array([[1., 1., 3.],
       [0., 1., 0.]])

一応欲しいものにはなっているけど、気持ちが悪い

原因

実は、tile()関数の問題ではない(なので解決までに時間がかかってしまった)

原因は列の指定の仕方にある

上のように単純に指定すると一次元の配列になる

列ベクトルの形のまま抽出するには、A[:, 1:2]と指定しないといけない

>>> A[:, 1]
array([1., 0.])
>>> A[:, 1:2]
array([[1.],
       [0.]])

しっかりできている

>>> np.tile(A[:, 1:2], (1, 3))
array([[1., 1., 1.],
       [0., 0., 0.]])

ヨシ!

>>> B + np.tile(A[:, 1:2], (1, 3))
array([[1., 1., 3.],
       [0., 1., 0.]])

そもそもtile()使う必要ない

列数が1で、行数は足される数に一致してるから、自動でブロードキャストしてくれる

>>> B + A[:, 1:2]
array([[1., 1., 3.],
       [0., 1., 0.]])

ただし、このときも列ベクトルとして抽出しないとエラーが出るので注意

>>> B + A[:, 1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (2,3) (2,)