numpy
前回、Pythonでリスト内の要素(文字列)を結合するjoin関数を紹介しました。
今回はnumpyで行列計算をする方法を紹介します。
まず行列とは数値を縦横に並べたもので、これを計算するには下の計算のように最初のカッコの中の数字は横に、次のカッコの中は縦に数字を取り、掛け合わせたものを足していくという特殊な計算を行います。
もちろんこのような複雑な計算は手で計算したら間違えやすいわけで、できれば計算機に任せたいのですが、通常の電卓では簡単には計算できません。
そこでPythonにやらせたらいいじゃない!というのが今回のお話です。
それでは始めていきましょう。
行列の作り方
まずは行列を作っていきます。
先ほど見ていただいた通り、行列は2つの次元をもっています(実はさらに3次元の行列や4次元の行列もあるそうですが、それはまた別のお話)。
そこでまずは2次元のリストを作成します。
m1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
m2 = [[2], [4], [6]]
print(m1)
print(m2)
print(m1 * m2)
実行結果
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[2], [4], [6]]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[9], line 6
4 print(m1)
5 print(m2)
----> 6 print(m1 * m2)
TypeError: can't multiply sequence by non-int of type 'list'
ただしこのままではあくまでも2次元リストであり、行列ではないので、掛け算(行列でいう内積)をするとエラーとなってしまいます。
またnumpyの配列(np.array)にすると計算はできるようになりますが、行列計算ではありません。
import numpy as np
m1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
m2 = np.array([[2], [4], [6]])
print(m1)
print(m2)
print(m1 * m2)
実行結果
[[1 2 3]
[4 5 6]
[7 8 9]]
[[2]
[4]
[6]]
[[ 2 4 6]
[16 20 24]
[42 48 54]]
2次元リストを行列として認識させるには「np.matrix(リスト)」とする必要があります。
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
m2 = np.matrix([[2], [4], [6]])
print(m1)
print(m2)
print(m1 * m2)
実行結果
[[1 2 3]
[4 5 6]
[7 8 9]]
[[2]
[4]
[6]]
[[ 28]
[ 64]
[100]]
また行列の内積を求めるのに「*」を用いましたが、他の方法として「np.dot(行列1, 行列2)」という方法、もしくは「行列1 @ 行列2」という方法があります。
import numpy as np
m1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
m2 = np.array([[2], [4], [6]])
print(m1)
print(m2)
print(np.dot(m1, m2))
print(m1 @ m2)
実行結果
[[1 2 3]
[4 5 6]
[7 8 9]]
[[2]
[4]
[6]]
[[ 28]
[ 64]
[100]]
[[ 28]
[ 64]
[100]]
逆行列の求め方
次に逆行列の求め方を見て見ましょう。
逆行列とはある行列にかけ合わせると単位行列となるものです。
例えばこんな感じで、左側の最初の行列に対して、2つ目の行列が逆行列、右側が単位行列です。
このような逆行列を求めるには「np.linalg.inv(行列)」を用います。
import numpy as np
m3 = np.matrix([[2, 5], [1, 3]])
m3_inv = np.linalg.inv(m3)
result = m3 * m3_inv
print(np.matrix(m3))
print(m3_inv)
print(result)
実行結果
[[2 5]
[1 3]]
[[ 3. -5.]
[-1. 2.]]
[[1. 0.]
[0. 1.]]
他にも「行列**-1」や「行列.I」としても逆行列を求めることができます。
import numpy as np
m3 = np.matrix([[2, 5], [1, 3]])
m3_inv1 = np.linalg.inv(m3)
m3_inv2 = m3**-1
m3_inv3 = m3.I
print(m3_inv1)
print(m3_inv2)
print(m3_inv3)
実行結果
[[ 3. -5.]
[-1. 2.]]
[[ 3. -5.]
[-1. 2.]]
[[ 3. -5.]
[-1. 2.]]
ただし全ての行列に対し逆行列が存在するわけではありません。
逆行列が存在しない場合、エラーとなってしまいます。
m1 = np.matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(m1)
print(np.linalg.inv(m1))
実行結果
[[1 2 3]
[4 5 6]
[7 8 9]]
---------------------------------------------------------------------------
LinAlgError Traceback (most recent call last)
Cell In[27], line 4
1 m1 = np.matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
3 print(m1)
----> 4 print(np.linalg.inv(m1))
File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/numpy/linalg/linalg.py:561, in inv(a)
559 signature = 'D->D' if isComplexType(t) else 'd->d'
560 extobj = get_linalg_error_extobj(_raise_linalgerror_singular)
--> 561 ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj)
562 return wrap(ainv.astype(result_t, copy=False))
File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/numpy/linalg/linalg.py:112, in _raise_linalgerror_singular(err, flag)
111 def _raise_linalgerror_singular(err, flag):
--> 112 raise LinAlgError("Singular matrix")
LinAlgError: Singular matrix
このような場合でも逆行列のような行列(擬似逆行列)を得る方法があり、「np.linalg.pinv(行列)」とすることで得られます。
m1 = np.matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
m1_inv = np.linalg.pinv(m1)
result = m1 * m1_inv
print(m1)
print(m1_inv)
print(result)
実行結果
[[1 2 3]
[4 5 6]
[7 8 9]]
[[-6.38888889e-01 -1.66666667e-01 3.05555556e-01]
[-5.55555556e-02 3.36727575e-17 5.55555556e-02]
[ 5.27777778e-01 1.66666667e-01 -1.94444444e-01]]
[[ 0.83333333 0.33333333 -0.16666667]
[ 0.33333333 0.33333333 0.33333333]
[-0.16666667 0.33333333 0.83333333]]
擬似逆行列はどのような行列でも得ることができるのですが、逆行列は特定の条件の場合のみ存在します。
逆行列が存在するかどうかを調べるには「np.linalg.det(行列)」を使います。
結果が0となったら逆行列は存在せず、1となったら逆行列が存在します。
m1 = np.matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
m3 = np.matrix([[2, 5], [1, 3]])
print(np.linalg.det(m1))
print(np.linalg.det(m3))
実行結果
0.0
1.0
行列の縦と横を入れ替える方法
行列の縦と横を入れ替えるには「行列.T」、もしくは「行列.transpose()」を用います。
m1 = np.matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(m1)
print(m1.T)
print(m1.transpose())
実行結果
[[1 2 3]
[4 5 6]
[7 8 9]]
[[1 4 7]
[2 5 8]
[3 6 9]]
[[1 4 7]
[2 5 8]
[3 6 9]]
次回は無名関数lambdaを紹介します。
ではでは今回はこんな感じで。
コメント