NumPy配列の対角成分を完全マスター!diag・diagonalの使い方と対角行列作成術
NumPyで行列の対角成分を扱う操作は、線形代数や機械学習において頻繁に使用されます。本記事では、numpy.diag()
とnumpy.diagonal()
を使った対角成分の抽出と対角行列の作成方法を、実践的なサンプルコードとともに詳しく解説します。
対角成分・対角行列とは?
- 対角成分: 行列の主対角線上の要素(行番号と列番号が等しい要素)
- 対角行列: 主対角線以外のすべての要素が0である正方行列
1. numpy.diag() – 万能な対角操作関数
numpy.diag()
は、入力によって2つの異なる動作をする多機能な関数です。
1-1. 行列から対角成分を抽出
import numpy as np
# 3x3行列を作成
matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 主対角成分を抽出
diagonal = np.diag(matrix)
print(diagonal) # [1 5 9]
1-2. 1次元配列から対角行列を作成
# 1次元配列から対角行列を生成
arr = np.array([1, 5, 9])
diag_matrix = np.diag(arr)
print(diag_matrix)
# [[1 0 0]
# [0 5 0]
# [0 0 9]]
1-3. オフセット(k)による副対角線の操作
# 上の副対角線を抽出(k=1)
upper_diag = np.diag(matrix, k=1)
print(upper_diag) # [2 6]
# 下の副対角線を抽出(k=-1)
lower_diag = np.diag(matrix, k=-1)
print(lower_diag) # [4 8]
1-4. オフセット指定での対角行列作成
# 上の副対角線に値を配置
arr = np.array([2, 6])
upper_diag_matrix = np.diag(arr, k=1)
print(upper_diag_matrix)
# [[0 2 0]
# [0 0 6]
# [0 0 0]]
# 下の副対角線に値を配置
arr = np.array([4, 8])
lower_diag_matrix = np.diag(arr, k=-1)
print(lower_diag_matrix)
# [[0 0 0]
# [4 0 0]
# [0 8 0]]
2. numpy.diagonal() – 対角成分抽出専用関数
numpy.diagonal()
は対角成分の抽出に特化した関数で、より高度な操作が可能です。
2-1. 基本的な使用方法
# 基本的な対角成分抽出
matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
diagonal = np.diagonal(matrix)
print(diagonal) # [1 5 9]
2-2. 多次元配列での対角成分抽出
# 3次元配列での対角成分抽出
tensor = np.random.rand(2, 3, 3)
print("3次元配列の形状:", tensor.shape)
# 最後の2次元で対角成分を抽出
diagonals = np.diagonal(tensor, axis1=-2, axis2=-1)
print("対角成分の形状:", diagonals.shape) # (2, 3)
2-3. 軸指定による柔軟な抽出
# 4x4行列での軸指定
large_matrix = np.arange(16).reshape(4, 4)
print("元の行列:")
print(large_matrix)
# axis1=0, axis2=1で対角成分抽出
diag_01 = np.diagonal(large_matrix, axis1=0, axis2=1)
print("対角成分:", diag_01) # [0 5 10 15]
3. 実践的な活用例
3-1. 単位行列の作成
# 単位行列を作成
identity = np.diag(np.ones(4))
print(identity)
# [[1. 0. 0. 0.]
# [0. 1. 0. 0.]
# [0. 0. 1. 0.]
# [0. 0. 0. 1.]]
# より簡潔な方法
identity_simple = np.eye(4)
print(np.array_equal(identity, identity_simple)) # True
3-2. 対角成分の操作
# 対角成分の値を変更
matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 対角成分を2倍にする
np.fill_diagonal(matrix, np.diag(matrix) * 2)
print(matrix)
# [[ 2 2 3]
# [ 4 10 6]
# [ 7 8 18]]
3-3. トレース(対角和)の計算
# 行列のトレースを計算
matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
trace_manual = np.sum(np.diag(matrix))
trace_builtin = np.trace(matrix)
print(f"手動計算: {trace_manual}") # 15
print(f"組み込み関数: {trace_builtin}") # 15
3-4. 対角優勢行列の作成
# 対角優勢行列(対角成分が他の要素の和より大きい)
n = 4
base_matrix = np.random.rand(n, n)
# 各行の非対角成分の和を計算し、対角成分をそれより大きくする
for i in range(n):
row_sum = np.sum(np.abs(base_matrix[i])) - np.abs(base_matrix[i, i])
base_matrix[i, i] = row_sum + 1
print("対角優勢行列:")
print(base_matrix)
4. 非正方行列での対角操作
4-1. 長方形行列の対角成分
# 3x5の長方形行列
rect_matrix = np.arange(15).reshape(3, 5)
print("長方形行列:")
print(rect_matrix)
# 対角成分を抽出(最小次元まで)
diag_rect = np.diag(rect_matrix)
print("対角成分:", diag_rect) # [0 6 12]
4-2. 異なるサイズでの対角行列作成
# 4x6の対角行列を作成
arr = np.array([1, 2, 3, 4])
diag_46 = np.zeros((4, 6))
np.fill_diagonal(diag_46, arr)
print("4x6対角行列:")
print(diag_46)
5. パフォーマンス比較とベストプラクティス
5-1. 大規模行列での性能比較
import time
# 大規模行列での性能テスト
large_matrix = np.random.rand(1000, 1000)
# numpy.diag()での抽出
start = time.time()
diag_result1 = np.diag(large_matrix)
time1 = time.time() - start
# numpy.diagonal()での抽出
start = time.time()
diag_result2 = np.diagonal(large_matrix)
time2 = time.time() - start
print(f"np.diag(): {time1:.6f}秒")
print(f"np.diagonal(): {time2:.6f}秒")
5-2. メモリ効率的な操作
# インプレース操作での対角成分変更
matrix = np.random.rand(5, 5)
original_matrix = matrix.copy()
# 対角成分を直接変更(メモリ効率的)
matrix.flat[::matrix.shape[1]+1] *= 2
print("対角成分が2倍になった行列:")
print(matrix)
6. よくあるエラーと対処法
6-1. 次元エラーの対処
# 1次元配列での誤った使用例
arr_1d = np.array([1, 2, 3])
try:
# これはエラーにならず、対角行列を作成
result = np.diag(arr_1d)
print("1次元配列 → 対角行列:")
print(result)
except Exception as e:
print(f"エラー: {e}")
6-2. オフセット範囲外の対処
# オフセットが範囲外の場合
matrix = np.array([[1, 2], [3, 4]])
large_offset = np.diag(matrix, k=5) # 空の配列が返される
print("範囲外オフセット結果:", large_offset) # []
7. 応用例:固有値問題での活用
# 対称行列の固有値分解での対角化
symmetric_matrix = np.array([[4, 2], [2, 3]])
eigenvals, eigenvecs = np.linalg.eigh(symmetric_matrix)
# 固有値で対角行列を作成
diagonal_eigenvals = np.diag(eigenvals)
print("固有値対角行列:")
print(diagonal_eigenvals)
# 対角化の確認
reconstructed = eigenvecs @ diagonal_eigenvals @ eigenvecs.T
print("元の行列との差:", np.allclose(symmetric_matrix, reconstructed))
まとめ
NumPyの対角操作関数を適切に使い分けることで、効率的な行列計算が可能になります。
主要なポイント:
np.diag()
: 対角成分抽出と対角行列作成の万能関数np.diagonal()
: 多次元配列での柔軟な対角成分抽出- オフセット(k)パラメータで副対角線も操作可能
- 非正方行列でも適切に動作
これらの関数を使いこなすことで、線形代数計算、機械学習、科学計算における様々な問題を効率的に解決できるでしょう。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座