NumPy配列ndarrayの対角成分の抽出、対角行列の作成(diag, diagonal)

二次元のNumPy配列numpy.ndarrayの対角成分を抽出するにはnumpy.diag()関数を使います。一次元の配列からそれを対角成分とする対角行列を作成することもできます。

numpy.diag — NumPy v1.15 Manual

numpy.diag()はnumpy.ndarrayを引数とする関数だが、numpy.ndarrayのメソッドとして対角成分を抽出するnumpy.ndarray.diagonal()も用意されています。

numpy.ndarray.diagonal — NumPy v1.15 Manual

ここでは以下の内容について説明します。

numpy.diag()で対角成分を抽出 基本的な使い方 開始位置の指定: 引数k 正方行列ではない場合 多次元配列の場合 注意: 戻り値はread-onlyのビュー(v1.14.5の場合)

numpy.diag()で対角行列を生成 基本的な使い方 開始位置の指定: 引数k 単位行列の生成

diagonal()メソッドの使い方

numpy.diag()で対角成分を抽出

基本的な使い方

以下のnumpy.ndarrayを例とします。

import numpy as np

a = np.arange(9).reshape((3, 3))

print(a)
# [[0 1 2]
#  [3 4 5]
#  [6 7 8]]

np.diag()の引数にnumpy.ndarrayを指定すると、対角成分が一次元配列として返される。

print(np.diag(a))
# [0 4 8]

開始位置の指定: 引数k

上の例のようにデフォルトは(0, 0)を開始位置として対角成分を抽出するが、引数kにオフセットを整数で指定できます。 正の整数を指定すると開始位置が右側(上側)に移動。範囲外を指定してもエラーにはならず、空の配列が返される。

print(np.diag(a, k=1))
# [1 5]

print(np.diag(a, k=2))
# [2]

print(np.diag(a, k=3))
# []

負の整数は開始位置が左側(下側)に移動。

print(np.diag(a, k=-1))
# [3 7]

print(np.diag(a, k=-2))
# [6]

print(np.diag(a, k=-3))
# []

正方行列ではない場合

正方行列でないnumpy.ndarrayもnp.diag()の引数として指定可能。引数kもそのまま使える。

a = np.arange(12).reshape((3, 4))

print(a)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

print(np.diag(a))
# [ 0  5 10]

print(np.diag(a, k=1))
# [ 1  6 11]

print(np.diag(a, k=-1))
# [4 9]

多次元配列の場合

三次元以上の多次元配列を指定するとエラーとなります。

a = np.arange(27).reshape((3, 3, 3))

print(a)
# [[[ 0  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 26]]]

# print(np.diag(a))
# ValueError: Input must be 1- or 2-d.

一次元配列の場合は次に示すようにその配列を対角成分とする対角行列を返す。

注意: 戻り値はread-onlyのビュー(v1.14.5の場合)

np.diag()の戻り値がビューかコピーかはバージョンによって異なる。

whether it returns a copy or a view depends on what version of numpy you are using. numpy.diag — NumPy v1.15 Manual

以下の例はバージョン1.14.5の場合。このバージョンではnp.diag()はread-only(書き換え禁止)のビューとして返される。

a = np.arange(9).reshape((3, 3))

print(a)
# [[0 1 2]
#  [3 4 5]
#  [6 7 8]]

a_diag = np.diag(a)

print(a_diag)
# [0 4 8]

# a_diag[0] = 100
# ValueError: assignment destination is read-only

要素の値を書き換えたい場合はflags.writeable属性をTrueとします。ビューなので元の配列の要素の値も変更される。

a_diag.flags.writeable = True

a_diag[0] = 100

print(a_diag)
# [100   4   8]

print(a)
# [[100   1   2]
#  [  3   4   5]
#  [  6   7   8]]

ビューではなくコピーを取得したい場合はcopy()を使います。この場合、元の配列の要素の値は変更されない。

a_diag_copy = np.diag(a).copy()

print(a_diag_copy)
# [100   4   8]

a_diag_copy[1] = 100

print(a_diag_copy)
# [100 100   8]

print(a)
# [[100   1   2]
#  [  3   4   5]
#  [  6   7   8]]

numpy.diag()で対角行列を生成

基本的な使い方

np.diag()は対角行列の生成にも使える。 引数に一次元配列を指定するとその配列を対角成分とした対角行列が生成される。

import numpy as np

a = np.array([10, 20, 30])

print(a)
# [10 20 30]

print(np.diag(a))
# [[10  0  0]
#  [ 0 20  0]
#  [ 0  0 30]]

引数はnumpy.ndarrayでなくPyhton標準のリストやタプルでも問題ありません。

print(np.diag([100, 200, 300]))
# [[100   0   0]
#  [  0 200   0]
#  [  0   0 300]]

開始位置の指定: 引数k

対角成分の抽出と同様に引数kで開始位置を指定できます。 第一引数の配列の要素がすべて収まる正方行列が返される。

print(np.diag(a, k=1))
# [[ 0 10  0  0]
#  [ 0  0 20  0]
#  [ 0  0  0 30]
#  [ 0  0  0  0]]

print(np.diag(a, k=-2))
# [[ 0  0  0  0  0]
#  [ 0  0  0  0  0]
#  [10  0  0  0  0]
#  [ 0 20  0  0  0]
#  [ 0  0 30  0  0]]

単位行列の生成

単位行列(対角成分がすべて1の対角行列)はnp.diag()を使って生成することもできるが、専用の関数np.identity()が便利。

numpy.identity — NumPy v1.15 Manual

np.identity()では第一引数にサイズ、第二引数に型dtypeを指定する(デフォルトはNoneで多くの場合はfloatになる)。

print(np.diag([1, 1, 1]))
# [[1 0 0]
#  [0 1 0]
#  [0 0 1]]

print(np.identity(3))
# [[1. 0. 0.]
#  [0. 1. 0.]
#  [0. 0. 1.]]

print(np.identity(3, int))
# [[1 0 0]
#  [0 1 0]
#  [0 0 1]]

np.identity()を使うと配列をone-hot表現に簡単に変換できます。以下の記事を参照。

diagonal()メソッドの使い方

numpy.ndarrayのメソッドとして、対角成分を抽出するdiagonal()もあります。

numpy.ndarray.diagonal — NumPy v1.15 Manual

import numpy as np

a = np.arange(9).reshape((3, 3))

print(a)
# [[0 1 2]
#  [3 4 5]
#  [6 7 8]]

print(a.diagonal())
# [0 4 8]

diagonal()では引数offsetがdiag()の引数kに相当します。

print(a.diagonal(offset=1))
# [1 5]

print(a.diagonal(offset=3))
# []

print(a.diagonal(offset=-2))
# [6]

正方行列でない場合も同様。

a = np.arange(12).reshape((3, 4))

print(a)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

print(a.diagonal())
# [ 0  5 10]

print(a.diagonal(offset=1))
# [ 1  6 11]

diagonal()メソッドはnp.diag()関数のように対角行列の生成はできない。一次元配列から呼び出すとエラーになるので注意。

a = np.arange(3)

print(a)
# [0 1 2]

# a.diagonal()
# ValueError: diag requires an array of at least two dimensions

シェア

関連カテゴリー

Python NumPy

NumPyのarange, linspaceの使い方(連番や等差数列を生成) NumPyの配列ndarrayの欠損値np.nanを他の値に置換 Pythonでメソッドチェーンを改行して書く NumPyの配列ndarrayの欠損値np.nanを含む行や列を削除 Python, OpenCV, NumPyで画像のアルファブレンドとマスク処理 NumPy配列ndarrayを任意の最小値・最大値に収めるclip NumPyで任意の行・列を削除するdeleteの使い方 NumPyで全要素を同じ値で初期化した配列ndarrayを生成 NumPyでRGB画像の色チャンネルを分離して単色化、白黒化、色交換 Python, NumPyで行列の演算(逆行列、行列式、固有値など) NumPy配列ndarrayをイミュータブル(書き換え禁止)に設定 NumPyで空の配列ndarrayを生成するemptyとempty_like NumPyでCSVファイルを読み込み・書き込み(入力・出力) Pythonのリストと配列とnumpy.ndarrayの違いと使い分け NumPy配列ndarrayをタイル状に繰り返し並べるnp.tile

Last Updated: 6/26/2019, 10:34:03 PM