置換行列

置換行列

置換行列

 任意の行列 $A$ に単位行列 $I$ を掛けると、$A$ が元の形を保つことはすでに学んでいます:
 
\[IA=AI=I\]
 すなわち単位行列 $I$ は恒等変換行列です。
 いま、$3\times 3$ 単位行列と、$3\times 3$ 正方行列
 
\[I=\begin{bmatrix}1&0&0\\0&1&0\\0&0&1\end{bmatrix}
,\quad A=\begin{bmatrix}a&b&c\\d&e&f\\g&h&i\end{bmatrix}\]
を考えて、$I$ の 2 行目と 3 行目を入れ替えた行列
 
\[P_{23}=\begin{bmatrix}1&0&0\\0&0&1\\0&1&0\end{bmatrix}\]
を定義して行列 $A$ の左側に掛けてみると、
 
\[P_{23}A=\begin{bmatrix}1&0&0\\0&0&1\\0&1&0\end{bmatrix}
\begin{bmatrix}a&b&c\\d&e&f\\g&h&i\end{bmatrix}
=\begin{bmatrix}a&b&c\\g&h&i\\d&e&f\end{bmatrix}\]
となって、$A$ の 2 行目と 3 行目を入れ替えることがわかります。

 一般に、$n\times n$ の単位行列の $i$ 行目と $j$ 行目を入れ替えた行列 $P_{ij}$ を任意の行列 $A$ に左側から掛けると、$A$ の $i$ 行目と $j$ 行目を入れ替えます。$A$ の右側から掛けると列を交換します。このような変換をほどこす行列 $P_{ij}$ を 置換行列 とよびます。置換行列はこの先の記事で扱う LUP 分解など、線型代数の実用的な分野で用いられます。
 

配列の行を入れ替える

 NumPy で 配列の行を入れ替える方法 を解説します。
 最初に 3×3 の 2 次元配列を作成しておきます。

# リストSWP-1

import numpy as np

x = np.arange(1, 10).reshape(3, 3)

print(x)
[[1 2 3]
 [4 5 6]
 [7 8 9]]

 NumPy ではファンシーインデックス (インデックスリストを渡して複数要素に同時アクセスする手法) を使って特定の行にアクセスできます。たとえば、x[[1, 2]] は 1 行目と 2 行目を縦積みした配列を取得します。

# リストSWP-2

print(x[[1, 2]])
[[4 5 6]
 [7 8 9]]

 x[[2, 1]] は 2 行目と 1 行目を取得します。

# リストSWP-3

print(x[[2, 1]])
[[7 8 9]
 [4 5 6]]

 ファンシーインデックスはメモリへの直接アクセスなので、x[[1, 2]] に x[[2, 1]] を代入すると、結果として 1 行目と 2 行目が交換されることになります (もとの配列が変更されます)。

# リストSWP-4

x[[1, 2]] = x[[2, 1]]

print(x)
[[1 2 3]
 [7 8 9]
 [4 5 6]]

 一般に、x[[i, j]] = x[[j, i]] という記述で i 行と j 行を入れ替えられます。

def swap_rows(x, i, j):
    x[[i, j]] = x[[j, i]]

 とはいえ、場合によっては元の配列を変更したくないと思うかもしれません。以下に定義する swap_rows()関数 は、受け取った配列のコピーを作成して行を入れ替えます。

# リストSWP-5

def swap_rows(x, i, j):
    a = x.copy()
    a[[i, j]] = a[[j, i]]
    return a

 swap_rows() の動作を確認するために、新しい 2 次元配列 y を作成しておきます。

# リストSWP-6

# 乱数生成器のシードを0に固定
np.random.seed(0)

# 要素をランダムに決定して配列を生成
y = np.random.randint(0, 10, (5, 5))

print(y)
[[5 0 3 3 7]
 [9 3 5 2 4]
 [7 6 8 8 1]
 [6 7 7 8 1]
 [5 9 8 9 4]]

 y を swap_rows() に渡して 2 行目と 4 行目を入れ替えます。

# リストSWP-7

# yの2行目と4行目を交換
sy = swap_rows(y, 1, 3)

print(sy)
[[5 0 3 3 7]
 [6 7 7 8 1]
 [7 6 8 8 1]
 [9 3 5 2 4]
 [5 9 8 9 4]]