転置行列と実対称行列

当サイトではアフィリエイトプログラムを利用して商品を紹介しています。

【Pythonで学ぶ線形代数学講座(20)】転置行列と実対称行列

転置行列

$m\times n$ の行列
 \[A=\begin{bmatrix}a_{11}&a_{12} &\cdots &a_{1n}\\a_{21}&a_{22} &\cdots &a_{2n}\\\vdots & \vdots &\ddots &\vdots\\a_{m1}&a_{m2} &\cdots &a_{mn}\end{bmatrix}\]
について、$a_{ij}$ と $a_{ji}$ の位置を入れ替えた行列、すなわち主対角線 (左上から右下に伸びる対角線) で成分を折り返した行列
 \[\begin{bmatrix}a_{11}&a_{21} &\cdots &a_{m1}\\a_{12}&a_{22} &\cdots &a_{m2}\\\vdots & \vdots &\ddots &\vdots\\a_{1n}&a_{2n} &\cdots &a_{mn}\end{bmatrix}\]
を $A$ の 転置行列 (transpose) と定義し、$^tA$ または $A^T$ のように表します。また、行列 $A$ の転置行列を得ることを「$A$ を転置する」と言います。
 
Python 転置行列 (transpose)
NumPy で適当な行列を作って、転置してみましょう。ndarray の転置行列は T 属性で参照できます。

# python transpose

# In[1]

# ランダムな3×3行列を生成
rng = np.random.default_rng(117)
matrix = rng.integers(0, 10, (3, 3))

print(matrix)
# [[1 8 2]
#  [1 1 6]
#  [8 3 6]]
# In[2]

# 行列を転置
print(matrix_a.T)

# [[1 1 8]
#  [8 1 3]
#  [2 6 6]]

転置行列の性質

行列 $A$ の転置は線形操作です。
すなわち、任意の行列 $A,\ B$ とスカラー$k$ について
 \[\begin{align*}&(A+B)^T=A^T+B^T\tag{1}\\[6pt]&(kA)^T=k(A^T)\tag{2}\end{align*}\]
が成り立ちます。$A$ の転置行列を再び転置すると $A$ を得ます。
 \[(A^T)^T=A\tag{3}\]
行列積 $(AB)$ の転置は
 \[(AB)^T=B^TA^T\tag{4}\]
で与えられます。

# In[3]

matrix_b = rng.integers(0, 10, (3, 3))

print(matrix_b)
# [[5 1 3]
#  [9 6 2]
#  [3 3 1]]
# In[4]

# ABの転置
print((matrix_a @ matrix_b).T)

# [[83 32 85]
#  [55 25 44]
#  [21 11 36]]
# In[5]

# (Bの転置)(Aの転置)
print(matrix_b.T @ matrix_a.T)

# [[83 32 85]
#  [55 25 44]
#  [21 11 36]]

行列式は行列の転置によって不変です。つまり、$A$ の行列式 $\mathrm{det}A$ について、
 \[\mathrm{det}A=\mathrm{det}(A^T)\tag{5}\]
が成り立ちます。

# In[6]

# Aの行列式
det_a = np.linalg.det(matrix_a)
det_at = np.linalg.det(matrix_a.T)

print(f"Aの行列式: {np.round(det_a, 2)}")
print(f"Aの転置行列の行列式: {np.round(det_at, 2)}")

# Aの行列式: 314.0
# Aの転置行列の行列式: 314.0

逆行列の転置は転置行列の逆行列です:
 \[(A^{-1})^T=(A^T)^{-1}\tag{6}\]
$A$ が $m\times n$ の行列であるとき、$AA^T$ は $m\times m$, $A^TA$ は $n\times n$ の正方対称行列となります (対称行列については記事の後半を参照してください)。たとえば、$A$ が $2\times 3$ の矩形行列
 \[A=\begin{bmatrix}a&b&c\\d&e&f\end{bmatrix}\tag{7}\]
であるとき、$AA^T$ は $2\times 2$ の正方対称行列です。
 \[AA^T=\begin{bmatrix}a&b&c\\d&e&f\end{bmatrix}\begin{bmatrix}a&d\\b&e\\c&f\end{bmatrix}=\begin{bmatrix}a^2+b^2+c^2&ad+be+cf\\ad+be+cf&d^2+c^2+f^2\end{bmatrix}\tag{8}\]
$A^TA$ は $3\times 3$ 正方対称行列です。
 \[A^TA=\begin{bmatrix}a^2+d^2&ab+de&ac+df\\ab+de&b^2+e^2&bc+ef\\ac+df&bc+ef&c^2+f^2\end{bmatrix}\tag{9}\]

ndarray.T

NumPy で配列 (ndarray) を生成すると、自動的に転置配列もデータ属性として付与されます。転置配列は ndarray.T で参照します。

# ndarray_transpose

# In[1]

import numpy as np

# 乱数を初期化
np.random.seed(11)

# 要素を無作為に生成して4×4行列を定義
# [[1 2 8 2]
#  [8 3 9 1]
#  [1 5 3 2]
#  [6 6 8 5]]
a = np.random.randint(1, 10, (4, 4))

# aの転置行列を表示
print(a.T)

# [[1 8 1 6]
#  [2 3 5 6]
#  [8 9 3 8]
#  [2 1 2 5]]

numpy.transpose()

numpy.transpose() に行列 a を渡すと a の転置行列を返します。

# numpy_transpose

# In[1]

import numpy as np

# 乱数を初期化
np.random.seed(12)

# 要素を無作為に生成して3×5行列を定義
# [[7 2 3 4 4]
#  [1 7 2 5 6]
#  [3 7 1 6 9]]
a = np.random.randint(1, 10, (3, 5))

# aの転置行列
at = np.transpose(a)

print(at)

# [[7 1 3]
#  [2 7 7]
#  [3 2 1]
#  [4 5 6]
#  [4 6 9]]

実対称行列

転置によって自身を変えない正方行列、すなわち
 \[A^T=A\tag{10}\]
を満たす行列 $A$ を実対称行列(symmetric matrix)といいます。対称行列は主対角線に関して折り返すと重なるような行列です。たとえば、$3$ 次対称行列は
 \[\begin{bmatrix}d_1&a&b\\a&d_2&c\\b&c&d_3\end{bmatrix}\]
のように表せます。一般に対称行列の成分は $a_{ij}=a_{ji}$ という関係を満たしています。
 
以下は任意サイズの整数要素をもつ対称行列を生成する関数です。

# In[1]

# 対称正方行列自動生成関数
def symmetric_matrix_geterator(low, high, size, seed=0):
    rng = np.random.default_rng(seed)
    matrix = np.diag(rng.integers(low, high, size))
    for i in range(size):
        for j in range(size):
            if i != j:
                matrix[i][j] = matrix[j][i] = rng.integers(low=low, high=high)
    return matrix

引数 low と high には、それぞれ行列要素の下限値と上限値を指定します(ただし、high から 1 を引いた値が実際の上限値となります)。size は行列の大きさ、seed は乱数を固定するためのシード値です。3 × 3 の対称行列を作成してみましょう。

# In[2]

# 0~9の整数成分をもつ3×3の対称行列
matrix = symmetric_matrix_geterator(0, 10, 3, seed=1)

print(matrix)
# [[4 1 9]
#  [1 5 2]
#  [9 2 7]]

転置しても同じ行列になることを確認してみましょう。

# In[3]

# 対称行列は転置操作に対して不変であることを確認
print(matrix.T)

# [[4 1 9]
#  [1 5 2]
#  [9 2 7]]

対称行列の逆行列

対称行列の逆行列を転置すると
 \[(A^{-1})^T=(A^T)^{-1}=A^{-1}\tag{11}\]
となるので、対称行列の逆行列もまた対称行列です。先ほど生成した対称行列の逆行列を求めて、それが対称行列となっていることを確認してみます。

# In[4]

np.set_printoptions(precision=3)

# 対称行列の逆行列もまた対称行列であることを確認
matrix_inv = np.linalg.inv(matrix)

print(matrix_inv)
# [[-0.123 -0.044  0.171]
#  [-0.044  0.21  -0.004]
#  [ 0.171 -0.004 -0.075]]

任意の行列 $X$ について、
 \[(X^TX)^T=X^T(X^T)^T=X^TX\tag{12}\]
が成り立つので、$X^TX$ および $XX^T$ は対称行列となります。$X$ は正方行列でなくても構いません。たとえば
 \[X=\begin{bmatrix}a&b&c\\d&e&f\end{bmatrix}\tag{13}\]
とした場合、$XX^T$ と $X^TX$ は異なるサイズの行列ですが、どちらも対称行列となります。
 \[XX^T=\begin{bmatrix}a^2+b^2+c^2&ad+be+cf\\ad+be+cf&a^2+b^2+c^2\end{bmatrix}\tag{14}\]
\[X^TX=\begin{bmatrix}a^2+d^2&ab+de&ac+df\\ab+de&b^2+e^2&bc+ef\\ac+df&bc+ef&c^2+f^2\end{bmatrix}\tag{15}\]
以下のコードで具体的な例を計算させているので、確かめてみてください。

# In[5]

# 2×3サイズの行列を生成
rng = np.random.default_rng(0)
x = rng.integers(0, 10, size=(2, 3))

print(x)
# [[8 6 5]
#  [2 3 0]]
# In[6]

# X(X^T)を計算
xxt = x @ x.T

print(xxt)
# [[125  34]
#  [ 34  13]]
# In[7]

# (X^T)Xを計算
xtx= matrix.T @ matrix

print(xtx)
# [[ 98  27 101]
#  [ 27  30  33]
#  [101  33 134]]

講座の後半で、対称行列を複素数範囲まで拡張したエルミート行列について学びます。エルミート行列は対称行列を完全に包含する形で定義されるので、(固有ベクトルが直交するなどの)エルミート行列の性質は、そのまま対称行列に当てはまります。ですから、対称行列の重要な性質は「エルミート行列」でまとめて説明することにします。

 

コメント

  1. HNaito より:

    下記は誤植と思われますので、ご確認ください。
    転置行列の定義の最右下の要素で、a_nm → a_mn
    (1)式で、A+B^T → (A+B)^T
    (10)式で、A^T=T → A^T=A
    (10)式の下の行で、主対線 → 主対角線

    • あとりえこばと より:

      ありがとうございます。
      本当に助かります。
      ご指摘いただいた箇所はすべて訂正しておきました。
      また何か見つけたらよろしくお願いします m(_ _)m