対称行列とは?意味・性質と例、NumPyでの判定・作り方とeighによる固有値
対称行列とは、転置しても元の行列と同じになる正方行列(Aᵀ=A)のことで、対角線をはさんで向かい合う成分がすべて等しい(aᵢⱼ=aⱼᵢ)行列です。NumPyでは np.allclose(A, A.T) で判定でき、固有値は np.linalg.eigh() で求めます。
この記事では、対称行列の意味と例、覚えておきたい性質を先に整理し、そのあとでNumPyを使った判定・作り方・固有値分解のコードを実行結果つきで紹介します。コードはPython 3.12、NumPy 2.5.4、SciPy 1.18.1で実行しました(2026年10月15日確認)。
対称行列とは
n行n列の正方行列Aの(i, j)成分をaᵢⱼと書くとき、すべてのi, jについて aᵢⱼ=aⱼᵢ が成り立つ行列を対称行列といいます。行と列を入れ替える操作(転置)をしても変わらないので、式では Aᵀ=A と書きます。
見た目でいうと、左上から右下への対角線(主対角線)を鏡にして、左下と右上が鏡写しになっている行列です。
| 例 | 対称か | 理由 |
|---|---|---|
| [[1, 2, 3], [2, 4, 5], [3, 5, 6]] | 対称 | a₁₂=a₂₁=2、a₁₃=a₃₁=3、a₂₃=a₃₂=5 |
| [[1, 2], [3, 4]] | 対称でない | a₁₂=2 と a₂₁=3 が違う |
| 単位行列・対角行列 | 対称 | 対角線の外がすべて0なので必ず等しい |
| 2行3列の行列 | 対称でない | 正方行列でないと、転置で形が変わる |
対角成分(a₁₁、a₂₂、…)には条件がなく、どんな値でもかまいません。条件がかかるのは対角線の外側だけです。
交代行列(歪対称行列)との違い
Aᵀ=−A になる行列は交代行列(歪対称行列)と呼ばれます。こちらは向かい合う成分の符号が逆で、対角成分は必ず0です。そして、どんな正方行列Aも「対称行列+交代行列」に一通りに分けられます。
A = (A+Aᵀ)/2 + (A−Aᵀ)/2
前半が対称部分、後半が交代部分です。後で紹介する「非対称な行列を対称化する」操作は、この前半だけを取り出していることになります。
対称行列の主な性質
| 性質 | 内容 |
|---|---|
| 和とスカラー倍 | 対称行列どうしの和、対称行列の定数倍は対称行列 |
| 積 | 対称行列どうしの積は、一般には対称にならない(AB=BAのときだけ対称) |
| AᵀA と AAᵀ | どんな形の行列Aでも、AᵀA と AAᵀ は対称行列になる |
| 固有値 | 実数の対称行列の固有値はすべて実数 |
| 固有ベクトル | 互いに直交するように選べるので、直交行列Vを使って A=VΛVᵀ と対角化できる |
| 逆行列 | 逆行列が存在すれば、それも対称行列 |
「固有値が実数」「直交行列で対角化できる」という2つの性質は、統計や機械学習で対称行列がよく出てくる理由そのものです。共分散行列や、主成分分析(PCA)で固有値分解する行列はどれも対称行列です。
NumPyで対称行列かどうかを判定する
整数の行列なら array_equal で十分
import numpy as np
S = np.array([[1, 2, 3],
[2, 4, 5],
[3, 5, 6]])
N = np.array([[1, 2],
[3, 4]])
print(np.array_equal(S, S.T))
print(np.array_equal(N, N.T))
True
False
計算で作った行列は allclose を使う
浮動小数点の計算を経た行列は、理論上は対称でも、ごく小さな誤差でぴったり一致しないことがあります。次の例では、対称行列Bを使って A B Aᵀ を計算しています。数学的には必ず対称になる式です。
import numpy as np
rng = np.random.default_rng(0)
A = rng.random((4, 4))
B = rng.random((4, 4))
B = B + B.T # Bは対称
G = A @ B @ A.T # 理論上は対称
print(np.array_equal(G, G.T))
print(np.allclose(G, G.T))
print(np.abs(G - G.T).max())
False
True
8.881784197001252e-16
差は10の−16乗ほどですが、array_equal(完全一致)では「対称でない」と判定されてしまいます。計算結果を判定するときは、許容誤差つきで比べるnp.allclose()を使ってください。
SciPyの issymmetric を使う
SciPyには対称かどうかを判定する専用の関数scipy.linalg.issymmetricがあり、正方の2次元配列が対称かを返します(scipy.linalg.issymmetric)。既定では完全一致で判定し、atolやrtolを渡すと誤差を許容します。
import numpy as np
from scipy.linalg import issymmetric
S = np.array([[1.0, 2.0], [2.0, 3.0]])
print(issymmetric(S))
T = S.copy(); T[0, 1] += 1e-12
print(issymmetric(T))
print(issymmetric(T, atol=1e-10))
True
False
True
対称行列を作る
非対称な行列から対称部分を取り出す
先ほどの (A+Aᵀ)/2 を計算すると、任意の正方行列から対称行列が作れます。上三角の値をそのまま下三角にコピーしたいときはnp.triu()を使います。
import numpy as np
A = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
sym = (A + A.T) / 2 # 対称部分
skew = (A - A.T) / 2 # 交代(歪対称)部分
print(sym)
print(skew)
print(np.array_equal(sym + skew, A))
print(np.triu(A) + np.triu(A, 1).T) # 上三角をコピーして対称に
[[1. 3. 5.]
[3. 5. 7.]
[5. 7. 9.]]
[[ 0. -1. -2.]
[ 1. 0. -1.]
[ 2. 1. 0.]]
True
[[1 2 3]
[2 5 6]
[3 6 9]]
交代部分の対角成分がすべて0になっていることも確認できます。np.triu()のk引数の意味は「NumPyのtriu・tril・triの使い方」で解説しています。
AᵀA で作る(積の対称性も確認)
import numpy as np
A = np.array([[1, 2], [2, 3]])
B = np.array([[0, 1], [1, 0]])
print(A + B)
print(A @ B)
print(np.array_equal(A @ B, (A @ B).T))
M = np.array([[1, 2, 3], [4, 5, 6]])
print(M.T @ M)
print(M @ M.T)
[[1 3]
[3 3]]
[[2 1]
[3 2]]
False
[[17 22 27]
[22 29 36]
[27 36 45]]
[[14 32]
[32 77]]
対称行列AとBの和は対称ですが、積A @ Bは対称になっていません。一方、2行3列の長方形の行列Mからでも、Mᵀ M(3行3列)と M Mᵀ(2行2列)はどちらも対称行列になります。
対称行列の固有値は eigh で求める
対称行列の固有値・固有ベクトルは、汎用のnp.linalg.eig()ではなくnp.linalg.eigh()で求めるのが基本です。NumPyの公式ドキュメントでは、eighはエルミート行列または実対称行列のための関数で、固有値を昇順で返すと説明されています(numpy.linalg.eigh、2026年10月15日確認)。
import numpy as np
S = np.array([[2.0, 1.0],
[1.0, 2.0]])
w, V = np.linalg.eigh(S)
print(w)
print(V)
print(np.allclose(V.T @ V, np.eye(2))) # 固有ベクトルは直交
print(np.allclose(V @ np.diag(w) @ V.T, S)) # S = V Λ V^T
[1. 3.]
[[-0.70710678 0.70710678]
[ 0.70710678 0.70710678]]
True
True
固有値は昇順に1と3、固有ベクトルを並べた行列Vは直交行列(VᵀV=I)で、S=VΛVᵀ が成り立っています。前の節の性質表がそのまま確認できます。
対称でない行列では、固有値が実数にならないことがあります。90度回転の行列と、よく似た形の対称行列を比べます。
import numpy as np
R = np.array([[0.0, -1.0],
[1.0, 0.0]]) # 90度回転(対称ではない)
print(np.linalg.eigvals(R))
S = np.array([[0.0, 1.0],
[1.0, 0.0]]) # 対称行列
print(np.linalg.eigvals(S))
[0.+1.j 0.-1.j]
[ 1.+0.j -1.+0.j]
注意:eigh は対称かどうかをチェックしない
eighは入力が対称であることを前提にしていて、既定では下三角部分だけを使って計算します(引数UPLO='L')。対称でない行列を渡してもエラーにならず、別の行列の答えが返ってきます。
import numpy as np
N = np.array([[2.0, 5.0],
[1.0, 2.0]]) # 対称ではない
print(np.linalg.eigh(N).eigenvalues)
print(np.linalg.eigvals(N))
[1. 3.]
[ 4.23606798+0.j -0.23606798+0.j]
eighは右上の5を無視し、[[2, 1], [1, 2]] として計算しています。eighを使う前に、対称であることをnp.allclose(A, A.T)で確かめておくと安全です。
正定値対称行列とコレスキー分解
対称行列のうち、固有値がすべて正のものを正定値行列といいます。どんな0でないベクトルxに対しても xᵀAx>0 になる行列です。正定値かどうかは、np.linalg.eigvalsh()で固有値の符号を見るか、コレスキー分解(A=LLᵀ)が成功するかで確かめられます。
import numpy as np
S = np.array([[2.0, 1.0], [1.0, 2.0]])
x = np.array([1.0, -1.0])
print(x @ S @ x)
print(np.linalg.eigvalsh(S))
P = np.array([[1.0, 2.0], [2.0, 1.0]])
print(np.linalg.eigvalsh(P))
try:
np.linalg.cholesky(P)
except np.linalg.LinAlgError as e:
print("LinAlgError:", e)
2.0
[1. 3.]
[-1. 3.]
LinAlgError: Matrix is not positive definite
Pは対称行列ですが、固有値に−1があるため正定値ではなく、コレスキー分解は失敗します。「対称」と「正定値」は別の条件なので、混同しないようにしましょう。
データ分析で出てくる対称行列:共分散行列
身長と体重のような複数の変数の共分散行列は、変数Aと変数Bの共分散と、BとAの共分散が同じなので、必ず対称行列になります。
import numpy as np
data = np.array([[170, 65], [160, 55], [180, 75], [175, 68]], dtype=float)
C = np.cov(data, rowvar=False)
print(C)
print(np.allclose(C, C.T))
print(np.linalg.eigvalsh(C))
L = np.linalg.cholesky(C)
print(np.allclose(L @ L.T, C))
[[72.91666667 70.41666667]
[70.41666667 68.91666667]]
True
[ 0.47160336 141.36172997]
True
この共分散行列は固有値が2つとも正なので正定値で、コレスキー分解もできます。大きいほうの固有値(約141.4)に対応する固有ベクトルの方向が、データがもっとも大きく散らばっている方向で、これが主成分分析の第1主成分にあたります。
共分散行列やPCAを機械学習の中で使いこなしたい人には、テックジムのAIエンジニア養成コース(16章で機械学習とディープラーニングを学ぶコース)の第1章「教師なし学習と自然言語処理入門」でPCAを、第6章「AIのための統計学入門」で確率分布などの統計の基礎を学べます。
よくある質問
Q. 対称行列とは何ですか?
転置しても元と同じになる正方行列(Aᵀ=A)のことです。対角線をはさんで向かい合う成分がすべて等しく、aᵢⱼ=aⱼᵢ が成り立ちます。対角成分には条件がありません。
Q. 対称行列の固有値はなぜ実数になるのですか?
実数の対称行列はエルミート行列の特別な場合で、エルミート行列の固有値はすべて実数になることが証明されています。さらに固有ベクトルを互いに直交するように選べるため、直交行列で対角化できます。
Q. NumPyで対称行列かどうかを判定するには?
np.allclose(A, A.T) を使います。整数だけの行列なら np.array_equal(A, A.T) でもかまいませんが、計算で作った行列は誤差でぴったり一致しないことがあるため、許容誤差つきの allclose が安全です。SciPyの scipy.linalg.issymmetric も使えます。
Q. eig と eigh はどう使い分けますか?
対称行列(またはエルミート行列)には eigh を使います。固有値が実数の昇順で返り、固有ベクトルは直交します。ただし eigh は対称かどうかをチェックせず下三角だけで計算するため、対称でない行列には eig を使います。
Q. 対称行列どうしの積は対称行列になりますか?
一般にはなりません。AとBが対称でも、ABが対称になるのは AB=BA が成り立つ場合だけです。和や定数倍は必ず対称行列になります。
まとめ
対称行列は Aᵀ=A を満たす正方行列で、固有値がすべて実数になり、直交行列で対角化できるという扱いやすい性質を持っています。NumPyでは判定にnp.allclose(A, A.T)、対称化に(A + A.T) / 2、固有値分解にnp.linalg.eigh()を使うのが基本です。eighは対称性をチェックしないので、渡す前に判定しておくことを忘れないでください。行列の積や逆行列など、行列計算全般の書き方は「Pythonで行列計算|NumPyの積・転置・逆行列とエラーの直し方」にまとめています。
NumPy|行列・線形代数の関連記事
行列演算やブロードキャストなど、線形代数まわりの記事です。




