Pythonで行列の和を計算する
行列の定義と和の計算
リストによる定義と計算
Pythonで行列の計算をするときは、NumPyやSymPyモジュールを使うことが一般的で実用的ではありませんが、計算の流れを知るためリストによる表現からはじめます。ここでは、2つの行列をリストm_a、m_bとして定義して、2つの行列の和を求めます。それでは、行列を定義します。
行列の定義
- m_a = [[3, 2, 4],
- [5, 1 ,2],
- [3, 4 ,5]]
- m_b = [[1, 3, 2],
- [6, 2, 4],
- [2, 8, 3]]
行列の和は、要素同士の合計なので、はじめに合計を計算するための配列m_s1を空のリストとして定義し、for文で各要素の合計を計算した結果をappendメソッドでリストに追加します。
リストによる行列の和 ~ 最も単純な方法
- m_add1 = []
- for row in range(len(m_a)):
- temp = []
- for col in range (len(m_a[0])):
- temp.append(m_a[row][col]+m_b[row][col])
- m_add1.append(temp)
- m_add1
結果は次の通り、うまく計算することができました。
[[4, 5, 6], [11, 3, 6], [5, 12, 8]]
しかし何ともさえない方法なので、zip関数を使って2つのリストから同時に要素を取り出す方法を試してみます。
行列の和 ~ PythonらしくZipを使う方法
- m_add2 = []
- for row_a, row_b in zip(m_a, m_b):
- temp = []
- for elm_a,elm_b in zip(row_a,row_b):
- temp.append(elm_a + elm_b)
- m_add2.append(temp)
- m_add2
結果は、同じです。少しPythonらしくなりましたが、さらにリスト内包表記を使って計算します。
リスト内包表記による行列の和
- m_add3 = [[elm_a + elm_b for elm_a, elm_b in zip(row_a,row_b)] for row_a,row_b in zip(m_a,m_b)]
- m_add3
1行で計算できるのでとても便利ですが、リスト内包表記は2つのリストを扱うとわかりにくくなるのが難点です。
lambda式による行列の和
- m_add4=list(map(lambda row_a,row_b: list(map(lambda elm_a, elm_b:elm_a+ elm_b,row_a,row_b)), m_a, m_b))
- m_add4
こちらも結果は同じです。
リストを使った計算はPythonのプログラミングの練習にはなりますが手間がかかるので、行列の計算にはNumPyモジュールを使うのが一般的です。
NumPyによる定義と計算
NumPyモジュールの配列にはndarrayとmatrixの2つの形式があり、表記の仕方が異なります。まず、一般的なndarrayからです。ndarrayにはベクトル演算という機能があり、同じサイズの配列の算術演算では、同位要素(同じ場所の要素)ごとに計算されます。
NumPyのインポートと、ndarrayによる行列の定義
- import numpy as np
- na_a = np.array([[3, 2, 4],
- [5, 1 ,2],
- [3, 4 ,5]])
- na_b = np.array([[1, 3, 2],
- [6, 2, 4],
- [2, 8, 3]])
- na_add = na_a + na_b
- na_add
結果は、次の通り計算結果はndarray形式になります。
array([5, 7, 9])となります。次に、matrixによる方法です。
NumPyのmatrixによる行列の定義
- nm_a = np.matrix([[3, 2, 4],
- [5, 1 ,2],
- [3, 4 ,5]])
- nm_b = np.matrix([[1, 3, 2],
- [6, 2, 4],
- [2, 8, 3]])
- nm_add = nm_a + nm_b
- nm_add
結果は次の通り計算結果はmatrix形式になります。
SymPyによる定義と計算
SymPyはPython library for symbolic mathematicsといわれるように、代数を扱うことができます。sympy.matrixによりベクトルを定義し、合計します。Pythonは変数を明示的に定義しなくてもよい仕様になっていますが、SymPyでは、s_a、s_bのようにsympy.symbolsとして定義する必要があります。
SymPy Matrixによる行列の定義と和の計算
- import sympy
- sn_a, sn_b = sympy.symbols('s_a s_b')
- sn_a = sympy.Matrix([[3, 2, 4],
- [5, 1 ,2],
- [3, 4 ,5]])
- sn_b = sympy.Matrix([[1, 3, 2],
- [6, 2, 4],
- [2, 8, 3]])
- sn_add = sn_a + sn_b
- sn_add
結果は次の通り。
これだけだと、わざわざ変数を定義するだけ手間がかかるだけですが、SymPyのすごさは、次のような代数計算ができることです。
Sympy Matrixによる行列の和の代数計算
- sympy.var('a_x1,a_x2,a_x3,a_y1,a_y2,a_y3,a_z1,a_z2,a_z3')
- sympy.var('b_x1,b_x2,b_x3,b_y1,b_y2,b_y3,b_z1,b_z2,b_z3')
- sa_a = sympy.Matrix([[a_x1,a_x2,a_x3],
- [a_y1,a_y2,a_y3],
- [a_z1,a_z2,a_z3]])
- sa_b = sympy.Matrix([[b_x1,b_x2,b_x3],
- [b_y1,b_y2,b_y3],
- [b_z1,b_z2,b_z3]])
- sa_add = sa_a+sa_b
- sa_add
ここでは、sv_sで2つのベクトルの和を計算しており、その中身は変数で格納されています。
次に、変数が格納されているベクトルにsubsメソッドで数値をしてすると、前例のように計算することができます。
Sympy Matrixの代数計算に数値を代入
- sa_add.subs([(a_x1, 3), (a_x2, 2),(a_x3, 4),(a_y1, 5), (a_y2, 1), (a_y3, 2), (a_z1, 3),(a_z2, 4), (a_z3, 5),
- (b_x1, 1), (b_x2, 3),(b_x3, 2),(b_y1, 6), (b_y2, 2), (b_y3, 4), (b_z1, 2),(b_z2, 8), (b_z3, 3)])
上手く計算することができました。