Intro to Python
行列
最終更新:
introtopython
目次
行列を作る
NumPyモジュールのarray関数を使う。以下は3行2列の行列を作成した例。
>>> import numpy as np
>>> mx = np.array([[1, 2], [3, 4], [5, 6]])
>>> print(mx)
[[1 2]
[3 4]
[5 6]]
>>> mx
array([[1, 2],
[3, 4],
[5, 6]])
>>> mx[0, 0]
1
>>> mx[2, 1]
6
行列の要素を取り出す際に指定するインデックスは、0から始まる0および正値の整数であることに注意。
行列を作る
numpyモジュールのarray関数を使う。引数にリストを指定すると、それがそのまま行列(ndarray型)になる。
>>> import numpy as np
>>> np.array([[1, 3, 5], [2, 4, 6]])
array([[1, 3, 5],
[2, 4, 6]])
>>> n = [[1, 2], [3, 4]]
>>> print(n)
[[1, 2], [3, 4]]
>>> np.array(n)
array([[1, 2],
[3, 4]])
>>> mx = np.array(n)
>>> type(mx)
<class 'numpy.ndarray'>
行列の行数と列数を得る
shape変数を使う。以下は、2行3列の行列から行数(2)と列数(3)を得る例。
>>> import numpy as np
>>> mx = np.array([[1, 2, 3], [4, 5, 6]])
>>> mx.shape
(2, 3)
>>> mx.shape[0]
2
>>> mx.shape[1]
3
行列の様々な情報を得る
>>> import numpy as np
>>> mx = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
>>> print(mx)
[[1 2]
[3 4]
[5 6]
[7 8]]
>>> print('次元 {}'.format(mx.ndim))
次元 2
>>> print('全要素数 {}'.format(mx.size))
全要素数 8
>>> nrow, ncol = mx.shape
>>> print('行数 {}'.format(nrow))
行数 4
>>> print('列数 {}'.format(ncol))
列数 2
>>> print(mx[2, 1])
6
>>> print(mx[3, 1])
8
転置行列を作る
NumPyモジュールのndarrayを使う場合はT属性(「アトリビュート」とも)を使う。以下は、2行3列の行列を転置させた例(つまり3行2列の行列を作る)。
>>> import numpy as np
>>> mx1 = np.array([[1, 2, 3], [4, 5, 6]])
>>> mx1[1, 2]
6
>>> np.array(mx1).T
array([[1, 4],
[2, 5],
[3, 6]])
>>> mx2 = np.array(mx1).T
>>> mx2
array([[1, 4],
[2, 5],
[3, 6]])
>>> mx2[2, 1]
6
転置行列を求める
Tプロパティを使う。
>>> import numpy as np
>>> mx = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> print(mx)
[[1 2 3]
[4 5 6]
[7 8 9]]
>>> print(mx.T)
[[1 4 7]
[2 5 8]
[3 6 9]]
>>> mx = np.array([[1, 2, 3], [4, 5, 6]])
>>> print(mx)
[[1 2 3]
[4 5 6]]
>>> print(mx.T)
[[1 4]
[2 5]
[3 6]]
行列の掛け算を行う(積を求める)
NumPyモジュールのndarrayを使用した例。
>>> import numpy as np
>>> a1 = np.array([[1, 2], [3, 4]])
>>> a2 = np.array([[5, 6, 7], [8, 9, 10]])
>>> print(a1)
[[1 2]
[3 4]]
>>> print(a2)
[[ 5 6 7]
[ 8 9 10]]
>>> np.dot(a1, a2)
array([[21, 24, 27],
[47, 54, 61]])
行列の掛け算
dotメソッドを使う。最後の例のとおり、掛けられる行列の列数と掛ける行列の行数が同じでなければ計算することはできない。
>>> mx1 = np.array([[-1, 0, 3], [8, 1, -5]])
>>> mx2 = np.array([[3, 4, 0], [-2, 1, 2]])
>>> mx3 = np.array([[4, -3, 7], [2, 0, -1], [1, 5, 0]])
>>> print(mx1)
[[-1 0 3]
[ 8 1 -5]]
>>> print(mx2)
[[ 3 4 0]
[-2 1 2]]
>>> print(mx3)
[[ 4 -3 7]
[ 2 0 -1]
[ 1 5 0]]
>>> np.dot(mx1, mx3)
array([[ -1, 18, -7],
[ 29, -49, 55]])
>>> np.dot(mx2, mx3)
array([[ 20, -9, 17],
[ -4, 16, -15]])
>>> np.dot(mx1, mx2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<__array_function__ internals>", line 5, in dot
ValueError: shapes (2,3) and (2,3) not aligned: 3 (dim 1) != 2 (dim 0)
行列式を求める
linalg.detメソッドを使う。
>>> mx = np.array([[3]])
>>> mx
array([[3]])
>>> np.linalg.det(mx)
3.0000000000000004
>>> mx = np.array([[1, 2], [3, 4]])
>>> mx
array([[1, 2],
[3, 4]])
>>> np.linalg.det(mx)
-2.0000000000000004
>>> mx = np.array([[0, 3, 2, -1], [-4, 6, 1, 5], [0, -2, 3, -1], [-1, 0, 0, 2]])
>>> mx
array([[ 0, 3, 2, -1],
[-4, 6, 1, 5],
[ 0, -2, 3, -1],
[-1, 0, 0, 2]])
>>> np.linalg.det(mx)
27.999999999999986
逆行列を求める
linalg.invメソッドを使う。
>>> mx = np.array([[3]])
>>> mx
array([[3]])
>>> np.linalg.inv(mx)
array([[0.33333333]])
>>> mx = np.array([[1, 2], [3, 4]])
>>> mx
array([[1, 2],
[3, 4]])
>>> np.linalg.inv(mx)
array([[-2. , 1. ],
[ 1.5, -0.5]])
>>> mx = np.array([[3, -3, 1], [3, 2, 0], [-1, -5, 1]])
>>> mx
array([[ 3, -3, 1],
[ 3, 2, 0],
[-1, -5, 1]])
>>> np.linalg.inv(mx)
array([[ 1. , -1. , -1. ],
[-1.5, 2. , 1.5],
[-6.5, 9. , 7.5]])
正則ではない行列(行列式の値が0)の場合は、linalg.invメソッドはエラーを返す。
>>> mx = np.array([[1, 4, 7], [2, 5, 8], [3, 6, 9]])
>>> mx
array([[1, 4, 7],
[2, 5, 8],
[3, 6, 9]])
>>> np.linalg.det(mx)
0.0
>>> np.linalg.inv(mx)
Traceback (most recent call last):
(表示省略)
numpy.linalg.LinAlgError: Singular matrix
QR分解を行う
行列AをQR分解で行列Qと行列Rに分解することを考える。
A = Q R
行列QはQTQ=I(Iは単位行列)となる直交行列。行列Rは上三角行列(対角成分と対角成分より上の要素はすべて0以外で、対角成分より下の要素はすべて0)。
linalg.qrを使うと、それぞれQR分解した際の行列Qと行列Rが得られる。
>>> import numpy as np
>>> import scipy.linalg as linalg
>>> a = np.array([[1, 2, 3], [4, 5, 6], [9, 9, 8]])
>>> print(a)
[[1 2 3]
[4 5 6]
[9 9 8]]
>>> q, r = linalg.qr(a)
>>> print(q)
[[-0.10101525 -0.71840915 -0.6882472 ]
[-0.40406102 -0.60253671 0.6882472 ]
[-0.90913729 0.34761733 -0.22941573]]
>>> print(r)
[[ -9.89949494 -10.40457121 -10.00051019]
[ 0. -1.32094586 -2.98950905]
[ 0. 0. 0.22941573]]
QTQ = I となるか試す。
>>> print(np.dot(q.T, q))
[[ 1.00000000e+00 -1.50980479e-16 -9.33624473e-17]
[-1.50980479e-16 1.00000000e+00 1.17405362e-16]
[-9.33624473e-17 1.17405362e-16 1.00000000e+00]]
一般逆行列を求める
linalg.pinvメソッドを使う。
>>> import numpy as np
>>> mx = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
>>> print(mx)
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[13 14 15 16]]
>>> np.linalg.det(mx)
-1.820448242817726e-31
>>> np.linalg.inv(mx)
array([[ 1.50119988e+15, -3.75299969e+14, -3.75299969e+15,
2.62709978e+15],
[-1.95155984e+16, 1.95155984e+16, 1.95155984e+16,
-1.95155984e+16],
[ 3.45275971e+16, -3.79052969e+16, -2.77721977e+16,
3.11498974e+16],
[-1.65131986e+16, 1.87649984e+16, 1.20095990e+16,
-1.42613988e+16]])
>>> np.linalg.pinv(mx)
array([[-0.285 , -0.145 , -0.005 , 0.135 ],
[-0.1075, -0.0525, 0.0025, 0.0575],
[ 0.07 , 0.04 , 0.01 , -0.02 ],
[ 0.2475, 0.1325, 0.0175, -0.0975]])
一般逆行列の定義を満たしているか否か確認。
>>> mxi = np.linalg.pinv(mx)
>>> np.dot(np.dot(mx, mxi), mx)
array([[ 1., 2., 3., 4.],
[ 5., 6., 7., 8.],
[ 9., 10., 11., 12.],
[13., 14., 15., 16.]])
当然、正方行列でなくとも求めることができる。
>>> mx = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
>>> print(mx)
[[1 2 3 4]
[5 6 7 8]]
>>> np.linalg.det(mx)
(表示省略)
numpy.linalg.LinAlgError: Last 2 dimensions of the array must be square
>>> np.linalg.inv(mx)
(表示省略)
numpy.linalg.LinAlgError: Last 2 dimensions of the array must be square
>>> np.linalg.pinv(mx)
array([[-5.50000000e-01, 2.50000000e-01],
[-2.25000000e-01, 1.25000000e-01],
[ 1.00000000e-01, -1.38777878e-17],
[ 4.25000000e-01, -1.25000000e-01]])
>>> mxi = np.linalg.pinv(mx)
>>> np.dot(np.dot(mx, mxi), mx)
array([[1., 2., 3., 4.],
[5., 6., 7., 8.]])
linalg.pinvメソッドはムーア・ペンローズ一般逆行列を数値的に求めるメソッドのため、求まった一般逆行列は近似値であることに注意。ムーア・ペンローズ一般逆行列の定義の4つの式について、比較をした例は以下のとおり。すべての要素がTrueにならないことがわかる。
>>> np.dot(np.dot(mx, mxi), mx) == mx
array([[False, False, False, True],
[False, False, False, False]])
>>> np.dot(np.dot(mxi, mx), mxi) == mxi
array([[False, False],
[False, True],
[False, False],
[False, False]])
>>> np.dot(mx, mxi).T == np.dot(mx, mxi)
array([[ True, False],
[False, True]])
>>> np.dot(mxi, mx).T == np.dot(mxi, mx)
array([[ True, False, False, False],
[False, True, False, True],
[False, False, True, True],
[False, True, True, True]])
連立一次方程式を解く
solveメソッドを使う。以下の連立一次方程式を解く(解はx=3,y=2)。
x + 2y = 7
3x - 4y = 1
>>> import numpy as np
>>> mxaa = np.array([[1, 2], [3, -4]])
>>> mxy = np.array([7, 1])
>>> mxaa
array([[ 1, 2],
[ 3, -4]])
>>> mxy
array([7, 1])
>>> np.linalg.solve(mxaa, mxy)
array([3., 2.])
同じく以下の連立一次方程式を解く(解はx=2,y=-3,z=-14)。
3x - 3y + z = 1
3x + 2y = 0
-1x - 5y + z = -1
>>> mxaa = np.array([[3, -3, 1], [3, 2, 0], [-1, -5, 1]])
>>> mxy = np.array([1, 0, -1])
>>> mxaa
array([[ 3, -3, 1],
[ 3, 2, 0],
[-1, -5, 1]])
>>> mxy
array([ 1, 0, -1])
>>> np.linalg.solve(mxaa, mxy)
array([ 2., -3., -14.])
行列の和と差を求める
ndarray型に+演算子または-演算子を使う。行列の和と差の定義(行の数と列の数が同じ行列同士の各成分を足す、引く)から、二つの行列の行数と列数が一致しない場合はエラーが発生する。
>>> import numpy as np
>>> mxaa1 = np.array([[1, 2, 3], [6, 4, 2]])
>>> mxbb1 = np.array([[1, 1, 0], [2, 3, 8]])
>>> print(mxaa1)
[[1 2 3]
[6 4 2]]
>>> print(mxbb1)
[[1 1 0]
[2 3 8]]
>>> mxaa1 + mxbb1
array([[ 2, 3, 3],
[ 8, 7, 10]])
>>> mxaa2 = np.array([[1, 3], [2, 4]])
>>> mxbb2 = np.array([[7, 9], [5, 1]])
>>> print(mxaa2)
[[1 3]
[2 4]]
>>> print(mxbb2)
[[7 9]
[5 1]]
>>> mxaa2 - mxbb2
array([[-6, -6],
[-3, 3]])
>>> mxaa1 + mxbb2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (2,3) (2,2)
>>> mxaa1 - mxbb2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (2,3) (2,2)
行列のスカラー倍を求める
ndarray型に*演算子を使う。それぞれスカラー(数や関数のこと)と行列を指定する。
>>> import numpy as np
>>> a = 3
>>> mxxx = np.array([[1, 2, 3], [2, 3, 4], [2, 5, 6]])
>>> print(mxxx)
[[1 2 3]
[2 3 4]
[2 5 6]]
>>> a * mxxx
array([[ 3, 6, 9],
[ 6, 9, 12],
[ 6, 15, 18]])
行列の積を求める
行列Aと行列Bの積ABを求めるには、numpyモジュールのdot関数を使う。引数にそれぞれndarray型を指定する。行列の乗法は、左側の行列Aの列の数と右側の行列Bの行の数が一致している場合のみ求めることができる(そのような定義になっている)。左右の列数と行数が一致しない場合はエラーが発生する。
>>> import numpy as np
>>> mxaa1 = np.array([[1, 2, 3], [2, 3, 4], [2, 5, 6]])
>>> mxbb1 = np.array([[1, 0, 1], [0, 1, 0], [0, 1, 1]])
>>> print(mxaa1)
[[1 2 3]
[2 3 4]
[2 5 6]]
>>> print(mxbb1)
[[1 0 1]
[0 1 0]
[0 1 1]]
>>> np.dot(mxaa1, mxbb1)
array([[ 1, 5, 4],
[ 2, 7, 6],
[ 2, 11, 8]])
>>> mxaa2 = np.array([[1, 0, 1], [0, 1, 0]])
>>> mxbb2 = np.array([[1, 2], [0, 1], [0, -2]])
>>> print(mxaa2)
[[1 0 1]
[0 1 0]]
>>> print(mxbb2)
[[ 1 2]
[ 0 1]
[ 0 -2]]
>>> np.dot(mxaa2, mxbb2)
array([[1, 0],
[0, 1]])
行列のアダマール積を求める
*演算子を使う。それぞれndarray型を指定する。