からっぽのしょこ

読んだら書く!書いたら読む!同じ事は二度調べ(たく)ない

6.3.4:行列のノルムの計算例と性質の導出【『スタンフォード線形代数入門』のノート】

はじめに

 『スタンフォード ベクトル・行列からはじめる最適化数学』の学習ノートです。
 「数式の行間埋め」や「Pythonを使っての再現」によって理解を目指します。本と一緒に読んでください。

 この記事は6.3.4節「行列ノルム」の内容です。
 行列のノルムの定義を確認して、行列ノルムを用いた計算と性質を導出します。また、NumPyライブラリでの扱い方を確認します。

【前の内容】

www.anarchive-beta.com

【他の内容】

www.anarchive-beta.com

【今回の内容】

6.3.4 行列のノルムの計算例と性質の導出

 3.1節では、ベクトルのノルム(vector norm)を確認しました。この節では、行列のノルム(matrix norm)の計算を確認します。

ベクトルノルムの定義

 まずは、ベクトルのユークリッドノルムの定義式を確認します。
 ベクトルノルムについては「3.1-2:ユークリッドノルム・ユークリッド距離の性質と計算例【『スタンフォード線形代数入門』のノート】 - からっぽのしょこ」を参照してください。

  m 次元ベクトル

 \displaystyle
\mathbf{a}
    = \begin{bmatrix}
          a_1 \\
          a_2 \\
          \vdots \\
          a_m
      \end{bmatrix}

のベクトルノルムは、「要素の二乗和の平方根」で定義されます(3.1節)。

 \displaystyle
\|\mathbf{a}\|
    = \sqrt{
          \sum_{i=1}^m
              a_i^2
      }

 ベクトルノルムの2乗は、「要素の二乗和」です。

 \displaystyle
\|\mathbf{a}\|^2
    = \sum_{i=1}^m
          a_i^2


 ベクトルを指定して、ユークリッドノルムを計算します。

# ベクトルを作成
a = np.array([0.0, 1.0, -2.3, 0.1])
print(a)
print(a.shape)

# 定義式によりベクトルノルムを計算
norm_a = np.sqrt(np.sum(a**2))
print(norm_a)

# 関数によりベクトルノルムを計算
norm_a = np.linalg.norm(a)
print(norm_a)
[ 0.   1.  -2.3  0.1]
(4,)
2.5099800796022262
2.5099800796022262

 ユークリッドノルムは np.linalg.norm() で計算できます。

行列ノルムの定義

 続いて、行列のユークリッドノルムの定義式を確認します。

  m \times n 行列のノルムを考えます。

 \displaystyle
\mathbf{A}
    = \begin{bmatrix}
          a_{1,1} & a_{1,2} & \cdots & a_{1,n} \\
          a_{2,1} & a_{2,2} & \cdots & a_{2,n} \\
          \vdots  & \vdots  & \ddots & \vdots \\
          a_{m,1} & a_{m,2} & \cdots & a_{m,n}
      \end{bmatrix}

  \mathbf{A} の行列ノルムは、「要素の二乗和の平方根」で定義されます。

 \displaystyle
\|\mathbf{A}\|
    = \sqrt{
          \sum_{i=1}^m \sum_{j=1}^n
              a_{i,j}^2
      }

  \mathbf{A} の行列ノルムの2乗は、「要素の二乗和」です。

 \displaystyle
\begin{aligned}
\|\mathbf{A}\|^2
   &= \left(
          \sqrt{
              \sum_{i=1}^m \sum_{j=1}^n
                  a_{i,j}^2
          }
      \right)^2
\\
   &= \sum_{i=1}^m \sum_{j=1}^n
          a_{i,j}^2
\end{aligned}


 行列を指定して、ユークリッドノルムを計算します。

# 行列を作成
A = np.array(
    [[0.0, 1.0, -2.3, 0.1], 
     [1.2, 4.0, -0.1, 0.0], 
     [4.1, -1.0, 0.0, 1.7]]
)
print(A)
print(A.shape)

# 定義式により行列ノルムを計算
norm_A = np.sqrt(np.sum(A**2))
print(norm_A)

# 関数により行列ノルムを計算
norm_A = np.linalg.norm(A)
print(norm_A)
[[ 0.   1.  -2.3  0.1]
 [ 1.2  4.  -0.1  0. ]
 [ 4.1 -1.   0.   1.7]]
(3, 4)
6.6670833203133135
6.6670833203133135

 行列ノルムも np.linalg.norm() で計算できます。

行列ノルムの計算例

 次は、ユークリッドノルムを用いた計算例を導出します。

ノルムの2乗

 行列  \mathbf{A} の列ベクトルを

 \displaystyle
\mathbf{a}_j
    = \begin{bmatrix}
          a_{1,j} \\
          a_{2,j} \\
          \vdots \\
          a_{m,j}
      \end{bmatrix}

として、行列ノルムの2乗を考えます。

 \displaystyle
\|\mathbf{A}\|^2
    = \sum_{i=1}^m \sum_{j=1}^n
          a_{i,j}^2

 総和の順番を入れ換えて、 n についての和を展開します。

 \displaystyle
\begin{aligned}
\|\mathbf{A}\|^2
   &= \sum_{j=1}^n \sum_{i=1}^m
          a_{i,j}^2
\\
   &= \sum_{i=1}^m a_{i,1}^2
      + \sum_{i=1}^m a_{i,2}^2
      + \cdots
      + \sum_{i=1}^m a_{i,n}^2
\end{aligned}

  n 個の項をそれぞれベクトルノルムの2乗に置き換えます。

 \displaystyle
\|\mathbf{A}\|^2
    = \|\mathbf{a}_1\|^2
      + \|\mathbf{a}_2\|^2
      + \cdots
      + \|\mathbf{a}_n\|^2

 行列ノルムの2乗は、「列ベクトルのノルムの二乗和」で計算できます。

 同様に、行列  \mathbf{A} の行ベクトルを

 \displaystyle
\mathbf{a}_i
    = \begin{bmatrix}
          a_{i,1} & a_{i,2} & \cdots & a_{i,n}
      \end{bmatrix}

として、行列ノルムの2乗を考えます。 m についての和を展開して、 m 個の項をそれぞれベクトルノルムの2乗に置き換えます。

 \displaystyle
\begin{aligned}
\|\mathbf{A}\|^2
   &= \sum_{i=1}^m \sum_{j=1}^n
          a_{i,j}^2
\\
   &= \sum_{j=1}^n a_{1,j}^2
      + \sum_{j=1}^n a_{2,j}^2
      + \cdots
      + \sum_{j=1}^n a_{m,j}^2
\\
   &= \|\mathbf{a}_1\|^2
      + \|\mathbf{a}_2\|^2
      + \cdots
      + \|\mathbf{a}_m\|^2
\end{aligned}

 「行ベクトルのノルムの二乗和」でも計算できます。

 行列ノルムの2乗を計算します。

# 定義式により行列ノルムの2乗を計算
norm2_A = np.sum(A**2)
print(norm2_A)

# 関数により行列ノルムの2乗を計算
norm2_A = np.linalg.norm(A)**2
print(norm2_A)

# ベクトルノルムの2乗和により行列ノルムの2乗を計算
norm2_A = 0.0
for j in range(A.shape[1]):
    # 列ベクトルを抽出
    a_j = A[:, j]
    
    # 列ベクトルのノルムの2乗を加算
    norm2_A += np.linalg.norm(a_j)**2
print(norm2_A)

# ベクトルノルムの2乗和により行列ノルムの2乗を計算
norm2_A = 0.0
for i in range(A.shape[0]):
    # 行ベクトルを抽出
    a_i = A[i]
    
    # 行ベクトルのノルムの2乗を加算
    norm2_A += np.linalg.norm(a_i)**2
print(norm2_A)
44.45
44.449999999999996
44.44999999999999
44.45

 計算方法によってプログラム上の計算誤差が生じます。

要素の二乗平均

 二乗平均については「1.4:内積の性質と計算例【『スタンフォード線形代数入門』のノート】 - からっぽのしょこ」を参照してください。

 行列の要素の二乗平均は、「要素の二乗和と要素数の商」で定義されます(1.4節)。

 \displaystyle
\begin{aligned}
\mathrm{ms}(\mathbf{A})
   &= \frac{
          \sum_{i=1}^m \sum_{j=1}^n
              a_{i,j}^2
      }{
          m n
      }
\\
   &= \frac{\|\mathbf{A}\|^2}{m n}
\end{aligned}

 「行列ノルムと要素数の商」で計算できます。

 行列の要素の二乗平均を計算します。

# 行・列数を取得
m, n = A.shape
print(m)
print(n)

# 定義式により二乗平均を計算
norm2_A = np.sum(A**2)
ms_A = norm2_A / m / n
print(ms_A)

# 関数により二乗平均を計算
ms_A = np.linalg.norm(A)**2 / A.size
print(ms_A)
3
4
3.704166666666667
3.704166666666666


要素の二乗平均平方根

 二乗平均平方根については「3.1-2:ユークリッドノルム・ユークリッド距離の性質と計算例【『スタンフォード線形代数入門』のノート】 - からっぽのしょこ」を参照してください。

 行列の要素の二乗平均平方根は、「二乗平均の平方根」で定義されます(3.1節)。

 \displaystyle
\begin{aligned}
\mathrm{rms}(\mathbf{A})
   &= \sqrt{
          \frac{
              \sum_{i=1}^m \sum_{j=1}^n
                  a_{i,j}^2
          }{
              m n
          }
      }
\\
   &= \frac{
          \sqrt{
              \sum_{i=1}^m \sum_{j=1}^n
                  a_{i,j}^2
          }
      }{
          \sqrt{m n}
      }
\\
   &= \frac{\|\mathbf{A}\|}{\sqrt{m n}}
\end{aligned}

 「行列ノルムと要素数の平方根の商」で計算できます。

 行列の要素の二乗平均平方根を計算します。

# 行・列数を取得
m, n = A.shape
print(m)
print(n)

# 定義式により二乗平均平方根を計算
norm2_A = np.sum(A**2)
ms_A = norm2_A / m / n
rms_A = np.sqrt(ms_A)
print(rms_A)

# 関数により二乗平均平方根を計算
rms_A = np.sqrt(np.linalg.norm(A)**2 / A.size)
print(rms_A)
3
4
1.9246211748462778
1.9246211748462776


行列ノルムの性質

 行列ノルムの性質を導出します。

転置行列のノルム

 行列  \mathbf{A} の転置行列  \mathbf{A}^{\top} のノルムを考えます。

 \displaystyle
\begin{aligned}
\|\mathbf{A}^{\top}\|
   &= \left\|
          \begin{bmatrix}
              a_{1,1} & \cdots & a_{1,n} \\
              \vdots  & \ddots & \vdots \\
              a_{m,1} & \cdots & a_{m,n}
          \end{bmatrix}^{\top}
      \right\|
\\
   &= \left\|
          \begin{bmatrix}
              a_{1,1} & \cdots & a_{m,1} \\
              \vdots  & \ddots & \vdots \\
              a_{1,n} & \cdots & a_{m,n}
          \end{bmatrix}
      \right\|
\end{aligned}

 行列ノルムの定義式より、要素の二乗和の平方根の式にします。

 \displaystyle
\begin{aligned}
\|\mathbf{A}^{\top}\|
   &= \sqrt{
          \sum_{j=1}^n \sum_{i=1}^m
              a_{i,j}^2
      }
\\
   &= \sqrt{
          \sum_{i=1}^m \sum_{j=1}^n
              a_{i,j}^2
      }
\\
   &= \|\mathbf{A}\|
\end{aligned}

 総和の順番を入れ換えても影響しないので、転置行列のノルムは、元の行列ノルムと一致します。

 転置行列のノルムを計算します。

# 行列ノルムを計算
norm_A = np.linalg.norm(A)
print(norm_A)

# 転置して行列ノルムを計算
norm_At = np.linalg.norm(A.T)
print(norm_At)
6.6670833203133135
6.6670833203133135

 元の行列のノルムと転置行列のノルムが一致するのを確認できます。

行列のスカラー倍のノルム

 スカラー  \gamma と行列  \mathbf{A} の積のノルムを考えます。

 \displaystyle
\begin{aligned}
\|\gamma \mathbf{A}\|
   &= \left\|
          \gamma
          \begin{bmatrix}
              a_{1,1} & \cdots & a_{1,n} \\
              \vdots  & \ddots & \vdots \\
              a_{m,1} & \cdots & a_{m,n}
          \end{bmatrix}
      \right\|
\\
   &= \left\|
          \begin{bmatrix}
              \gamma a_{1,1} & \cdots & \gamma a_{1,n} \\
              \vdots  & \ddots & \vdots \\
              \gamma a_{m,1} & \cdots & \gamma a_{m,n}
          \end{bmatrix}
      \right\|
\end{aligned}

 行列ノルムの定義式より、要素の二乗和の平方根の式にします。

 \displaystyle
\begin{aligned}
\|\gamma \mathbf{A}\|
   &= \sqrt{
          \sum_{i=1}^m \sum_{j=1}^n
              (\gamma a_{i,j})^2
      }
\\
   &= \sqrt{
          \gamma^2
          \sum_{i=1}^m \sum_{j=1}^n
              a_{i,j}^2
      }
\end{aligned}

 平方根の性質  \sqrt{x y} = \sqrt{x} \sqrt{y} \sqrt{x^2} = |x| より、項を分割して置き換えます。

 \displaystyle
\begin{aligned}
\|\gamma \mathbf{A}\|
   &= \sqrt{\gamma^2}
      \sqrt{
          \sum_{i=1}^m \sum_{j=1}^n
              a_{i,j}^2
      }
\\
   &= |\gamma|
      \|\mathbf{A}\|
\end{aligned}

 スカラー倍した行列のノルムは、「スカラーの絶対値と行列ノルムの積」で計算できます。

 行列のスカラー倍のユークリッドノルムを計算します。

# スカラを指定
gamma = -2.0

# 定義式により行列ノルムを計算
norm_gamA = np.sqrt(np.sum((gamma * A)**2))
print(norm_gamA)

# 関数により行列ノルムを計算
norm_gamA = np.abs(gamma) * np.linalg.norm(A)
print(norm_gamA)
13.334166640626627
13.334166640626627

 絶対値は np.abs() で計算できます。

 この記事では、行列のノルムを確認しました。次の記事では、行列とベクトルの積を確認します。

参考書籍

  • Stephen Boyd・Lieven Vandenberghe(著),玉木 徹(訳)『スタンフォード ベクトル・行列からはじめる最適化数学』講談社サイエンティク,2021年.

おわりに

 まだ5章の修正事項を放置したままで、6章の内容も既に順番が前後していてグダグダの予感ですが、進めていきます。

 2023年7月13日は、モーニング娘。の元リーダーの道重さゆみさんのお誕生日です!

 今も音楽活動を続けてくれていて嬉しい限りです。というのに、私は未だにライブに行けてません。今年こそは行きたーい🐰

 また、OCHA NORMAのメジャーデビュー1周年の日です!

 まだ1年?もう1年?冠番組にタイアップに新曲と素晴らしい活動っぷりです。
 オチャノーマということで、いくつか飛ばしてノルムについての記事を先に更新しました。

【次の内容】

www.anarchive-beta.com