線形代数ライブラリを作ろうと色々とプログラムを書いていたわけですが、なんとなくで転置行列をどう簡単に求めるかということを考え始めました。その時に思いついた転置行列の求め方を共有します。
一般解ぽいやつ(個人の見解)
まずは一般に使われそうな方法を考えてみました。
入力行列は3x2の行列として、求める転置行列は2x3とします。対応するインデックスの関係がわかりやすいように数値を設定してみます。
A = [
[11, 12],
[21, 22],
[31, 32]
]
At = []
j = 0
for i in range(len(A[j])):
row = []
for j in range(len(A)):
row.append(A[j][i])
At.append(row)
print(At)
これで動くはず...オーソドックスか知らんけど、二重ループ回すのが一般的な思考だと思ったので、これを一般解として提示しました。
ちなみに得られる出力はこちらです。
[[11, 21, 31], [12, 22, 32]]
多分大丈夫そう。
一般解ぽいやつを内包表記してみた
さきに示した一般解っぽいやつを内包表記を用いて書いてみます。
A = [
[11, 12],
[21, 22],
[31, 32]
]
j = 0
At = [
[A[j][i] for j in range(len(A))]
for i in range(len(A[j]))
]
print(At)
これも同様に同じ出力が得られます。
[[11, 21, 31], [12, 22, 32]]
【本題】zipと展開の合わせ技
さて、本題です。僕が思いついた手法は以下になります。
- A(入力行列)を展開して、行列から列ごとに展開
- zip()を用いて統合
- 内包表記にて転置行列を生成
こんな流れになります。言葉で言っても難しいので、コードをみてみます。
A = [
[11, 12],
[21, 22],
[31, 32]
]
At = [
list(row) for row in zip(*A)
]
print(At)
これだけです。
ただ、注意すべき点が一つだけあります。
**list()**としているところです。それはなぜかというと、zipで統合された物はtupleで帰ってきます。
内包表記において、listをとると次のような出力になります。
[(11, 21, 31), (12, 22, 32)]
tupleで返ってきても良いスクリプトであればそのままでも良いと思いますが、tupleだとイミュータブルなデータになってしまうので、大抵の場合**list()**でlist型に直してあげた方が良いことが多い気がします。
処理速度は測っていませんが、おそらく大きなサイズの行列の入力の時は高速に動くと思います(多分)
興味ある人は処理速度を計測してみてください。それでは、簡単な転置行列を求める方法の提案でした。(Pythonに限る)