Pythonので行列の和を計算する

ベクトルの定義と和の計算

リストによる定義と計算

Pythonで行列の計算をするときは、NumpyやSympyモジュールを使うことが一般的で実用的ではありませんが、計算の流れを知るためリストによる表現からはじめます。ここでは、2つの行列をリストm_am_bとして定義して、2つの行列の和を求めます。それでは、行列を定義します。

  1. # 行列の定義
  2. m_a = [[3, 2, 4],
  3. [5, 1 ,2],
  4. [3, 4 ,5]]
  5. m_b = [[1, 3, 2],
  6. [6, 2, 4],
  7. [2, 8, 3]]

ベクトルの和は、要素同士の合計なので、はじめに合計を計算するための配列m_s1を空のリストとして定義し、for文で各要素の合計を計算した結果をappendメソッドでリストに追加します。

  1. # リストによる行列の和 ~ 最も単純な方法
  2. m_s1 = []
  3. for i in range(len(m_a)):
  4. m_t = []
  5. for j in range (len(m_a[0])):
  6. m_t.append(m_a[i][j]+m_b[i][j])
  7. m_s1.append(m_t)

結果は次の通り、うまく計算することができました。

[[4, 5, 6], [11, 3, 6], [5, 12, 8]]

しかし何ともさえない方法なので、zip関数を使って2つのリストから同時に要素を取り出す方法を試してみます。

  1. # 行列の和 ~ PythonらしくZipを使う方法
  2. m_s2 = []
  3. for x, y in zip(m_a, m_b):
  4. m_t = []
  5. for xx,yy in zip(x,y):
  6. m_t.append(xx+yy)
  7. m_s2.append(m_t)
  8. m_s2

結果は、同じです。少しPythonらしくなりましたが、さらにリスト内包表記を使って計算します。

  1. # リスト内包表記による行列の和
  2. [[xx + yy for xx,yy in zip(x,y)] for x,y in zip(m_a,m_b)]

1行で計算できるのでとても便利ですが、リスト内包表記は2つのリストを扱うとわかりにくくなるのが難点です。

リストを使った計算はPythonのプログラミングの練習にはなりますが手間がかかるので、行列の計算にはNumpyモジュールを使うのが一般的です。

Numpyによる定義と計算

Numpyモジュールの配列にはndarrayとmatrixの2つの形式があり、表記の仕方が異なります。まず、一般的なndarrayからです。ndarrayにはベクトル演算という機能があり、同じサイズの配列の算術演算では、同位要素(同じ場所の要素)ごとに計算されます。

  1. # Numpyのインポートと、ndarrayによる行列の定義
  2. import numpy as np
  3. # 行列の定義
  4. n_a = np.array([[3, 2, 4],
  5. [5, 1 ,2],
  6. [3, 4 ,5]])
  7. n_b = np.array([[1, 3, 2],
  8. [6, 2, 4],
  9. [2, 8, 3]])
  10. n_a + n_b

結果は、次の通り計算結果はndarray形式になります。

sympyによる行列の数値計算
sympyによる行列の数値計算

array([5, 7, 9])となります。次に、matrixによる方法です。

  1. # Numpyのmatrixによる行列の定義
  2. nm_a = np.matrix([[3, 2, 4],
  3. [5, 1 ,2],
  4. [3, 4 ,5]])
  5. nm_b = np.matrix([[1, 3, 2],
  6. [6, 2, 4],
  7. [2, 8, 3]])
  8. nm_a + nm_b

結果は次の通り計算結果はmatrix形式になります。

sympyによる行列の数値計算
sympyによる行列の数値計算

Sympyによる定義と計算

SympyはPython library for symbolic mathematicsといわれるように、代数を扱うことができます。sympy.Matrixによりベクトルを定義し、合計します。Pythonは変数を明示的に定義しなくてもよい仕様になっていますが、Sympyでは、s_a、s_bのようにsympy.symbolsとして定義する必要があります。

  1. # Sympy Matrixによる行列の定義と和の計算
  2. import sympy
  3. \ sympy.init_printing()
  4. s_a, s_b = sympy.symbols('s_a s_b')
  5. s_a = sympy.Matrix([[3, 2, 4],
  6. [5, 1 ,2],
  7. [3, 4 ,5]])
  8. s_b = sympy.Matrix([[1, 3, 2],
  9. [6, 2, 4],
  10. [2, 8, 3]])
  11. s_a + s_b

結果は次の通り。

sympyによる行列の数値計算
sympyによる行列の数値計算

これだけだと、わざわざ変数を定義するだけ手間がかかるだけですが、Sympyのすごさは、次のような代数計算ができることです。

  1. # Sympy Matrixによる行列の和の代数計算
  2. a_x1,a_x2,a_x3,a_y1,a_y2,a_y3,a_z1,a_z2,a_z3 = sympy.symbols('a_x1,a_x2,a_x3,a_y1,a_y2,a_y3,a_z1,a_z2,a_z3')
  3. b_x1,b_x2,b_x3,b_y1,b_y2,b_y3,b_z1,b_z2,b_z3 = sympy.symbols('b_x1,b_x2,b_x3,b_y1,b_y2,b_y3,b_z1,b_z2,b_z3')
  4. sv_a = sympy.Matrix([[a_x1,a_x2,a_x3],
  5. [a_y1,a_y2,a_y3],
  6. [a_z1,a_z2,a_z3]])
  7. sv_b = sympy.Matrix([[b_x1,b_x2,b_x3],
  8. [b_y1,b_y2,b_y3],
  9. [b_z1,b_z2,b_z3]])
  10. sv_s= sv_a+sv_b
  11. sv_s

ここでは、sv_sで2つのベクトルの和を計算しており、その中身は変数で格納されています。

sympyによる行列の代数計算
sympyによる行列の代数計算

次に、変数が格納されているベクトルにsubsメソッドで数値をしてすると、前例のように計算することができます。

  1. Sympy Matrixの代数計算に数値を代入
  2. sv_s.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),
  3. (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)])

結果は同じように縦のベクトルで帰されます。