numpyのarrayとmatrixの書き方の違い
- はじめに
- ベクトルと行列ベクトル
- トレース,行列式と逆行列
- ベクトルの内積
- 行列とベクトルの積
- 行列の積
- 要素ごとの積 (アダマール積)
- ベクトルから行列 (テンソル積 ?)
- その他,関係ありそうだけど使ってない関数
- おわりに
はじめに
numpyの行列関連の演算がわからなくなってググることがよくある. また,動くことは動くがもう少し綺麗にならないかと思うこともよくある.
行列を表すために,numpyではarrayとmatrixを使うことができる.
しかし,掛け算の挙動などが,これら2つで異なるためにさらにややこしい印象がある.
自分用備忘録のためにarray,matrixそれぞれで特定の演算をするためにはどうすればいいかをまとめる.
色々な関数(特にnp.tensordotとか)でこれらの演算はできるが,自分が使うだろうなと思うものだけ書く.
from IPython.core.interactiveshell import InteractiveShell InteractiveShell.ast_node_interactivity = "all"
環境
import sys version = sys.version_info print("Python ",version.major,".",version.minor) import numpy as np print("numpy",np.__version__)
Python 3 . 6 numpy 1.11.3
ベクトルと行列ベクトル
以下では,ベクトルと行列
を使う.
x_a = np.array([i for i in range(1,3)]) x_m = np.mat([i for i in range(1,3)] ).T A_a = np.array([[i*2+j for i in range(2)] for j in range(2)]) A_m = np.mat([[i*2+j for i in range(2)] for j in range(2)]) "----np.array:----" A_a x_a "----np.matrix:----" A_m x_m
'----np.array:----'
array([[0, 2],
[1, 3]])
array([1, 2])
'----np.matrix:----'
matrix([[0, 2],
[1, 3]])
matrix([[1],
[2]])
np.matrix型のベクトルは転置することで列ベクトルにできる.
np.array型もnp.transpose([x_a])と書くと列ベクトルっぽくなるが,後の処理が面倒になるのでしない.
トレース,行列式と逆行列 
ありそうだけど,matrix型にdet関数がない.(ないよね?)
"----np.array:----" np.trace(A_a) np.linalg.det(A_a) np.linalg.inv(A_a) "----np.matrix:----" A_m.trace() np.linalg.det(A_m) A_m.I A_m**-1
'----np.array:----'
3
-2.0
array([[-1.5, 1. ],
[ 0.5, 0. ]])
'----np.matrix:----'
matrix([[3]])
-2.0
matrix([[-1.5, 1. ],
[ 0.5, 0. ]])
matrix([[-1.5, 1. ],
[ 0.5, 0. ]])
ベクトルの内積 
array型はnp.dotもしくはx_a.dotで明示的に書かないといけない.
"----np.array:----" np.dot(x_a, x_a) # arrayはnp.dotを使う. "----np.matrix:----" x_m.T * x_m # matrixは掛けるだけでいい
'----np.array:----' 5 '----np.matrix:----' matrix([[5]])
行列とベクトルの積 
上と同じ. matrix型は列ベクトルと行ベクトルがちゃんと結果に反映される.
"----np.array:----" np.dot(A_a, x_a) np.dot(x_a ,A_a) "----np.mat:----" A_m * x_m x_m.T * A_m
'----np.array:----'
array([4, 7])
array([2, 8])
'----np.mat:----'
matrix([[4],
[7]])
matrix([[2, 8]])
行列の積 
転置が入ったりすると,arrayではやや面倒になる.
matrixではべき乗はこの積になる.
"----np.array:----" np.dot(A_a, A_a) np.dot(np.transpose(A_a), A_a) # 転置が入ると面倒 "----np.mat:----" A_m * A_m A_m**2 # matrixのべき乗はこの積になる A_m.T * A_m
'----np.array:----'
array([[ 2, 6],
[ 3, 11]])
array([[ 1, 3],
[ 3, 13]])
'----np.mat:----'
matrix([[ 2, 6],
[ 3, 11]])
matrix([[ 2, 6],
[ 3, 11]])
matrix([[ 1, 3],
[ 3, 13]])
要素ごとの積 (アダマール積)
array型は*が要素ごとの積になっている.
一方でmatrix型はnp.multiply関数を使う必要がある.
特にべき乗などがある場合には一旦array型に変換するほうが楽かもしれない.
"----np.array:----" A_a * A_a A_a ** 3 # arrayのべき乗はこの積 "----np.mat:----" np.multiply(A_m, A_m) # matrixでは面倒 np.multiply(np.multiply(A_m, A_m), A_m) np.mat(A_m.A**3) # .Aで一旦arrayに変換したほうが短い
'----np.array:----'
array([[0, 4],
[1, 9]])
array([[ 0, 8],
[ 1, 27]])
'----np.mat:----'
matrix([[0, 4],
[1, 9]])
matrix([[ 0, 8],
[ 1, 27]])
matrix([[ 0, 8],
[ 1, 27]])
ベクトルから行列 (テンソル積 ?) 
(3次元以上の多次元配列のことをテンソルと呼ぶ文化圏にいます.)
ベクトルから行列を作ったり,行列からテンソルを作ったりする.
これはテンソル積なのか?
array型はtensordot(axes=0)を使う. matrix型はベクトル同士だとただ掛けるだけでできる. 一方で,出力がテンソルになる計算はできない.
"----np.array:----" np.tensordot(x_a, x_a, axes=0) # axesによって別の積になる np.tensordot(x_a, A_a, axes=0) "----np.mat:----" x_m * x_m.T # ベクトルはこれでいける x_m * A_m # 答えがテンソルになる演算はできない.
'----np.array:----'
array([[1, 2],
[2, 4]])
array([[[0, 2],
[1, 3]],
[[0, 4],
[2, 6]]])
'----np.mat:----'
matrix([[1, 2],
[2, 4]])
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-9-ede3e147096b> in <module>()
5 "----np.mat:----"
6 x_m * x_m.T
----> 7 x_m * A_m
/home/kei/anaconda3/envs/tensorflow/lib/python3.6/site-packages/numpy/matrixlib/defmatrix.py in __mul__(self, other)
341 if isinstance(other, (N.ndarray, list, tuple)) :
342 # This promotes 1-D vectors to row vectors
--> 343 return N.dot(self, asmatrix(other))
344 if isscalar(other) or not hasattr(other, '__rmul__') :
345 return N.dot(self, other)
ValueError: shapes (2,1) and (2,2) not aligned: 1 (dim 1) != 2 (dim 0)
その他,関係ありそうだけど使ってない関数
なんか色々あるけど,よく知らないので使ってない.
おわりに
記述が楽なので,matrixを使って書いてしまうことが多いけど,3次元以上はarrayで書くことになるので,慣れてないとバグを生む可能性が高い気がする. 皆さんどうしてるんですか.