CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: NumPy で正方行列を三角行列に加工する

今回は NumPy で正方行列を扱うとき、上三角行列とか下三角行列を取り出す方法について。 三角行列というのは、正方行列において対角要素より上の成分が全て 0 だったり、下の成分が全て 0 だったりする行列のこと。 ちなみに、最初この呼び方を知らなくて「行列 斜め 上」とかでたくさんぐぐった。

使った環境は次の通り。

$ sw_vers 
ProductName:    Mac OS X
ProductVersion: 10.12.6
BuildVersion:   16G1036
$ python --version
Python 3.6.3

インストール

ひとまず、何はともあれ NumPy はインストールしておく。

$ pip install numpy

サンプル用の正方行列を用意する

まずは、加工する前の正方行列を用意する。 今回は 1 ~ 25 の数字を入れた配列を 5 x 5 の正方行列にして使おう。

>>> import numpy as np
>>> array = np.arange(1, 5 * 5 + 1).reshape(5, 5)

中身はこんな感じ。

>>> array
array([[ 1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10],
       [11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20],
       [21, 22, 23, 24, 25]])

上三角行列 (対角要素あり)

まず、一番簡単なのは対角要素のある上三角行列かな。 これは単純に numpy.triu() 関数に正方行列を渡すだけで得られる。

>>> np.triu(array)
array([[ 1,  2,  3,  4,  5],
       [ 0,  7,  8,  9, 10],
       [ 0,  0, 13, 14, 15],
       [ 0,  0,  0, 19, 20],
       [ 0,  0,  0,  0, 25]])

簡単だね。

上三角行列 (対角要素なし)

続いて対角要素のない上三角行列を。 これは numpy.triu() 関数の k オプションに 1 を渡してやれば良い。

>>> np.triu(array, k=1)
array([[ 0,  2,  3,  4,  5],
       [ 0,  0,  8,  9, 10],
       [ 0,  0,  0, 14, 15],
       [ 0,  0,  0,  0, 20],
       [ 0,  0,  0,  0,  0]])

ちなみに k オプションの値は増やしたり減らすことで削る領域を調整できる。

>>> np.triu(array, k=2)
array([[ 0,  0,  3,  4,  5],
       [ 0,  0,  0,  9, 10],
       [ 0,  0,  0,  0, 15],
       [ 0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0]])
>>> np.triu(array, k=-1)
array([[ 1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10],
       [ 0, 12, 13, 14, 15],
       [ 0,  0, 18, 19, 20],
       [ 0,  0,  0, 24, 25]])

下三角行列 (対角要素あり)

(2017/12/06 追記)

下三角行列の効率的な加工方法を教えて頂きました。 転置行列を使うことで、短く書けるみたいです。 本文も、このやり方を使ったものに変更しました。 大変勉強になりました。この場を借りてお礼を申し上げます。


続いては下三角行列を見ていく。 下三角行列には、転置行列を使うことで効率的に加工できるようだ。

まず NumPy では行列の T アトリビュートから転置行列が得られる。 転置行列では、上三角と下三角が反転した状態になる。

>>> array.T
array([[ 1,  6, 11, 16, 21],
       [ 2,  7, 12, 17, 22],
       [ 3,  8, 13, 18, 23],
       [ 4,  9, 14, 19, 24],
       [ 5, 10, 15, 20, 25]])

そこで NumPy.triu() 関数を使うと上三角だけが残る。 転置する前においては下三角だった要素たちだ。

>>> np.triu(array.T)
array([[ 1,  6, 11, 16, 21],
       [ 0,  7, 12, 17, 22],
       [ 0,  0, 13, 18, 23],
       [ 0,  0,  0, 19, 24],
       [ 0,  0,  0,  0, 25]])

あとは、この状態から、さらに転置行列を取得することで元々の下三角行列が得られる。

>>> np.triu(array.T).T
array([[ 1,  0,  0,  0,  0],
       [ 6,  7,  0,  0,  0],
       [11, 12, 13,  0,  0],
       [16, 17, 18, 19,  0],
       [21, 22, 23, 24, 25]])

下三角行列 (対角要素なし)

対角要素なしの下三角行列の取り出しは、これまでの考え方の組み合わせでいける。

先ほどの考え方はそのままに、上三角行列を取り出すタイミングで k オプションを指定すれば良いだけ。

>>> np.triu(array.T, k=1).T
array([[ 0,  0,  0,  0,  0],
       [ 6,  0,  0,  0,  0],
       [11, 12,  0,  0,  0],
       [16, 17, 18,  0,  0],
       [21, 22, 23, 24,  0]])

めでたしめでたし。