NumPyで対称行列をマスター!生成・判定・活用法の完全ガイド
対称行列は線形代数、機械学習、科学計算において重要な役割を果たします。本記事では、NumPyを使った対称行列の生成方法、判定方法、そして実践的な活用例を詳しく解説します。初心者から上級者まで役立つ内容をお届けします。
対称行列とは?
対称行列は、転置行列が元の行列と等しい正方行列です。つまり、A = A.Tが成り立つ行列のことを指します。
数学的には:A[i,j] = A[j,i](すべてのi,jについて)
import numpy as np
# 対称行列の例
symmetric = np.array([[1, 2, 3],
[2, 4, 5],
[3, 5, 6]])
print("対称行列:")
print(symmetric)
1. 対称行列の判定方法
1-1. numpy.allclose()を使った基本的な判定
def is_symmetric(matrix):
return np.allclose(matrix, matrix.T)
# テスト用行列
matrix1 = np.array([[1, 2], [2, 3]]) # 対称
matrix2 = np.array([[1, 2], [3, 4]]) # 非対称
print(is_symmetric(matrix1)) # True
print(is_symmetric(matrix2)) # False
1-2. 数値誤差を考慮した判定
def is_symmetric_robust(matrix, rtol=1e-5, atol=1e-8):
"""数値誤差に対してロバストな対称性判定"""
return np.allclose(matrix, matrix.T, rtol=rtol, atol=atol)
# 浮動小数点誤差がある場合
noisy_symmetric = np.array([[1.0, 2.000001],
[2.000001, 3.0]])
print(is_symmetric_robust(noisy_symmetric)) # True
1-3. 正方行列チェック付きの判定
def is_symmetric_safe(matrix):
"""正方行列チェック付きの安全な対称性判定"""
matrix = np.asarray(matrix)
# 正方行列かチェック
if matrix.shape[0] != matrix.shape[1]:
return False
return np.allclose(matrix, matrix.T)
# 非正方行列のテスト
rect_matrix = np.array([[1, 2, 3], [4, 5, 6]])
print(is_symmetric_safe(rect_matrix)) # False
2. 対称行列の生成方法
2-1. ランダム対称行列の生成
def generate_random_symmetric(n, seed=None):
"""nxnのランダム対称行列を生成"""
if seed is not None:
np.random.seed(seed)
# ランダム行列を生成
A = np.random.rand(n, n)
# 対称化: (A + A.T) / 2
return (A + A.T) / 2
# 4x4対称行列を生成
sym_matrix = generate_random_symmetric(4, seed=42)
print("ランダム対称行列:")
print(sym_matrix)
print("対称性確認:", is_symmetric(sym_matrix))
2-2. 正定値対称行列の生成
def generate_positive_definite(n, seed=None):
"""正定値対称行列を生成(A.T @ A形式)"""
if seed is not None:
np.random.seed(seed)
A = np.random.rand(n, n)
return A.T @ A
# 正定値対称行列を生成
pd_matrix = generate_positive_definite(3, seed=42)
print("正定値対称行列:")
print(pd_matrix)
# 固有値で正定値性確認
eigenvals = np.linalg.eigvals(pd_matrix)
print("固有値:", eigenvals)
print("すべて正:", np.all(eigenvals > 0))
2-3. 指定した固有値を持つ対称行列
def symmetric_from_eigenvalues(eigenvals, seed=None):
"""指定した固有値を持つ対称行列を生成"""
if seed is not None:
np.random.seed(seed)
n = len(eigenvals)
# ランダムな直交行列を生成
Q, _ = np.linalg.qr(np.random.rand(n, n))
D = np.diag(eigenvals)
return Q @ D @ Q.T
# 固有値[5, 3, 1]を持つ対称行列
custom_sym = symmetric_from_eigenvalues([5, 3, 1], seed=42)
print("カスタム対称行列:")
print(custom_sym)
# 固有値確認
actual_eigenvals = np.linalg.eigvals(custom_sym)
print("実際の固有値:", np.sort(actual_eigenvals)[::-1])
2-4. 対称トープリッツ行列
def symmetric_toeplitz(first_row):
"""対称トープリッツ行列を生成"""
from scipy.linalg import toeplitz
return toeplitz(first_row)
# 対称トープリッツ行列
toep_sym = symmetric_toeplitz([1, 0.5, 0.25, 0.125])
print("対称トープリッツ行列:")
print(toep_sym)
3. 既存行列の対称化
3-1. 基本的な対称化
def symmetrize(matrix):
"""行列を対称化(上三角優先)"""
return (matrix + matrix.T) / 2
# 非対称行列を対称化
asymmetric = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
symmetric = symmetrize(asymmetric)
print("対称化後:")
print(symmetric)
3-2. 上三角または下三角優先の対称化
def symmetrize_upper(matrix):
"""上三角部分を使用して対称化"""
return np.triu(matrix) + np.triu(matrix, 1).T
def symmetrize_lower(matrix):
"""下三角部分を使用して対称化"""
return np.tril(matrix) + np.tril(matrix, -1).T
# テスト
matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
sym_upper = symmetrize_upper(matrix)
sym_lower = symmetrize_lower(matrix)
print("上三角優先:")
print(sym_upper)
print("下三角優先:")
print(sym_lower)
4. 対称行列の性質と活用
4-1. 固有値分解の効率化
# 対称行列の固有値分解(より効率的)
sym_matrix = generate_random_symmetric(4, seed=42)
# 一般的な固有値分解
eigenvals1, eigenvecs1 = np.linalg.eig(sym_matrix)
# 対称行列専用(より高速・安定)
eigenvals2, eigenvecs2 = np.linalg.eigh(sym_matrix)
print("eig()の固有値:", eigenvals1)
print("eigh()の固有値:", eigenvals2)
print("結果の一致:", np.allclose(np.sort(eigenvals1), np.sort(eigenvals2)))
4-2. 二次形式の計算
def quadratic_form(A, x):
"""二次形式 x^T A x を計算"""
return x.T @ A @ x
# 対称行列での二次形式
A = generate_positive_definite(3, seed=42)
x = np.array([1, 2, 3])
result = quadratic_form(A, x)
print(f"二次形式 x^T A x = {result}")
4-3. コレスキー分解
# 正定値対称行列のコレスキー分解
pd_matrix = generate_positive_definite(3, seed=42)
try:
L = np.linalg.cholesky(pd_matrix)
print("コレスキー分解 L:")
print(L)
# 復元確認
reconstructed = L @ L.T
print("復元確認:", np.allclose(pd_matrix, reconstructed))
except np.linalg.LinAlgError:
print("行列が正定値ではありません")
5. 実践的な応用例
5-1. 共分散行列の生成
def generate_covariance_matrix(n, correlation_strength=0.3, seed=None):
"""相関を持つ共分散行列を生成"""
if seed is not None:
np.random.seed(seed)
# 対角成分(分散)
variances = np.random.uniform(0.5, 2.0, n)
# 相関行列を生成
corr = np.eye(n)
for i in range(n):
for j in range(i+1, n):
corr_val = np.random.uniform(-correlation_strength,
correlation_strength)
corr[i,j] = corr[j,i] = corr_val
# 共分散行列 = D^(1/2) * R * D^(1/2)
D_sqrt = np.diag(np.sqrt(variances))
return D_sqrt @ corr @ D_sqrt
# 共分散行列を生成
cov_matrix = generate_covariance_matrix(4, seed=42)
print("共分散行列:")
print(cov_matrix)
print("対称性:", is_symmetric(cov_matrix))
5-2. カーネル行列の対称化
def rbf_kernel(X, gamma=1.0):
"""RBFカーネル行列を計算(対称性保証版)"""
n = X.shape[0]
K = np.zeros((n, n))
for i in range(n):
for j in range(i, n): # 上三角のみ計算
dist_sq = np.sum((X[i] - X[j]) ** 2)
K[i,j] = np.exp(-gamma * dist_sq)
if i != j:
K[j,i] = K[i,j] # 対称性を利用
return K
# テストデータ
X = np.random.rand(5, 2)
K = rbf_kernel(X)
print("RBFカーネル行列の対称性:", is_symmetric(K))
6. パフォーマンス最適化
6-1. 大規模行列での効率的な判定
def is_symmetric_fast(matrix, sample_ratio=0.1):
"""大規模行列での高速対称性判定(サンプリング)"""
n = matrix.shape[0]
sample_size = max(int(n * sample_ratio), 100)
# ランダムサンプリング
indices = np.random.choice(n, min(sample_size, n), replace=False)
for i in indices:
for j in indices:
if not np.isclose(matrix[i,j], matrix[j,i]):
return False
return True
# 大規模行列でのテスト
large_sym = generate_random_symmetric(1000, seed=42)
print("高速判定結果:", is_symmetric_fast(large_sym))
6-2. メモリ効率的な対称行列保存
def save_symmetric_compressed(matrix, filename):
"""対称行列の上三角部分のみを保存"""
upper_indices = np.triu_indices(matrix.shape[0])
upper_values = matrix[upper_indices]
np.savez_compressed(filename,
values=upper_values,
shape=matrix.shape[0])
def load_symmetric_compressed(filename):
"""圧縮保存された対称行列を復元"""
data = np.load(filename)
n = data['shape']
values = data['values']
matrix = np.zeros((n, n))
upper_indices = np.triu_indices(n)
matrix[upper_indices] = values
matrix = matrix + matrix.T - np.diag(np.diag(matrix))
return matrix
# 使用例
sym_matrix = generate_random_symmetric(100, seed=42)
save_symmetric_compressed(sym_matrix, 'symmetric_matrix.npz')
loaded_matrix = load_symmetric_compressed('symmetric_matrix.npz')
print("復元確認:", np.allclose(sym_matrix, loaded_matrix))
7. よくあるエラーと対処法
7-1. 数値誤差による判定失敗
# 計算による数値誤差の例
A = np.random.rand(3, 3)
symmetric_calc = A @ A.T # 理論上は対称
print("厳密判定:", np.array_equal(symmetric_calc, symmetric_calc.T))
print("誤差考慮判定:", np.allclose(symmetric_calc, symmetric_calc.T))
7-2. 非正方行列エラーの対処
def safe_symmetric_operation(matrix, operation='check'):
"""安全な対称行列操作"""
matrix = np.asarray(matrix)
if len(matrix.shape) != 2:
raise ValueError("2次元配列である必要があります")
if matrix.shape[0] != matrix.shape[1]:
raise ValueError("正方行列である必要があります")
if operation == 'check':
return is_symmetric(matrix)
elif operation == 'symmetrize':
return symmetrize(matrix)
# 使用例
try:
result = safe_symmetric_operation([[1, 2], [3, 4, 5]], 'check')
except ValueError as e:
print(f"エラー: {e}")
まとめ
NumPyを使った対称行列の操作をマスターすることで、線形代数計算が大幅に効率化されます。
重要なポイント:
np.allclose(A, A.T)で数値誤差を考慮した判定(A + A.T) / 2で簡単に対称化np.linalg.eigh()で対称行列専用の高速固有値分解- 正定値対称行列は
A.T @ Aで生成可能 - 大規模行列では上三角保存でメモリ節約
これらの技術を活用して、機械学習や科学計算における対称行列を効果的に扱いましょう。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座



