Home

拙著「Pythonデータ分析の第4章「行列演算とPythonスクリプト」の補足説明

配列の行・列の並べ替えと選択

 

配列の行および列の並べ替え選択、それらの固有分解特異値分解への応用についてスクリプト例を示す。

 

 

行・列の並べ替え

 

Numpyの配列(ndarray型)の要素は、i番目の要素をj番目に置くという指定によって並べ替えることができる。例えば、ndarray型の配列

 

a = numpy.array([1,2,3,4,5])

 

において、

 

[a[2],a[3],a[4],a[1],a[0]]

 

という形に並べ替えるときは、並べ替えのリストを

 

idx = [2,3,4,1,0]

 

と用意して、a[idx]とすればよい。

すなわち、次のスクリプト

 

import numpy as np

 

a = np.array([1,2,3,4,5])

print('a =', a)

idx = [2,3,4,1,0]

print('idx =', idx)

b = a[idx]

print('b =', b)

 

を実行すると、出力は

 

a = [1 2 3 4 5]

idx = [2, 3, 4, 1, 0]

b = [3 4 5 2 1]

 

となる。

行単位で並べ替えるときは、次のスクリプトのようになる。

 

A = np.array([[1,2,3],[4,5,6],[7,8,9]])

print('A =', A)

idx1 = [2,0,1]

print('idx1 =',idx1)

B = A[idx1]

print('B =', B)

 

実行結果の出力は以下のようになる。

 

A = [[1 2 3]

 [4 5 6]

 [7 8 9]]

idx1 = [2, 0, 1]

B = [[7 8 9]

 [1 2 3]

 [4 5 6]]

 

列単位で並べ換えるときのスクリプトは次のようになる。

 

C = A[:,idx1]

print('C =',C)

 

実行結果の出力は、以下のようである。

 

C = [[3 1 2]

 [6 4 5]

 [9 7 8]]

 

配列において、要素の大きさの順を得る関数としてnumpy.argsortがある。

次のスクリプトでは、リストaの要素の大きさの順が、それぞれの大きさが小さいものから何番目であるのかを示す配列idxとして得ることができる。

 

a = [5,3,1,2,4]

print('a =', a)

idx = np.argsort(a)

print('idx =', idx)

 

実行結果の出力は以下のようになる。

 

a = [5, 3, 1, 2, 4]

idx = [2 3 1 4 0]

 

すなわち、1番小さい要素はa[2]、次がa[3]、次がa[1]、次がa[4]、一番大きい要素がa[0]である。

したがって、aの要素を小さいものから順に並べ替えるスクリプトは以下のようになる。

 

a1 = np.array(a)[idx]

print('a1 =', a1)

 

aの要素の並べ替えにおいて、リスト型のanp.array(a)ndarray型に変換していることに注意。

実行結果の出力は以下の通りである。

 

a1 = [1 2 3 4 5]

 

要素を大きいもから小さいものの順に並べ替えるときは、以下のようにすればよい。-np.array(a)とマイナス記号-を付けてargsortしていることに注意。

 

idx = np.argsort(-np.array(a))

print('idx =', idx)

a2 = np.array(a)[idx]

print('a2 =', a2)

 

実行結果の出力は以下のようになる。

 

idx = [0 4 1 3 2]

a2 = [5 4 3 2 1]

 

 

 

行・列の選択

 

ndarray型の配列は、インデックスに論理値を指定することで選択できる。Trueで選択、Falseで非選択である。

例えば、次のスクリプト

 

import numpy as np

a = np.array([1,2,3,4,5])

print('a =', a)

a1 = a[[True, False, False, True, True]]

print('a1 =', a1)

 

を実行すると、以下の出力を得る。

 

a = [1 2 3 4 5]

a1 = [1 4 5]

 

したがって、配列から偶数の要素を選ぶスクリプト例は以下のようになる。

 

a = np.array([1,2,3,4,5])

ck = a % 2 ==0

print('ck =', ck)

a1 = a[ck]

print('a =', a)

print('a1 =', a1)

 

実行結果は、以下のような出力となる。

 

ck = [False  True False  True False]

a = [1 2 3 4 5]

a1 = [2 4]

 

2より大きい要素を選ぶスクリプト例は以下のようである。

 

ck1 = a > 2

print('ck1 =', ck1)

a2 = a[ck1]

print('a2 =', a2)

 

実行結果は、以下のような出力である。

 

ck1 = [False False  True  True  True]

a2 = [3 4 5]

 

2次元の配列の場合は、行単位、列単位で選択できる。サンプルスクリプトを以下に示す。

 

A = np.array([[1,2,3],[4,5,6], [7,8,9]])

print('A =\n', A)

ck = [True, False,True]

A1 = A[ck]                 #   行の選択

print('ck =', ck)

print('A1 =\n', A1)

A2 = A[:,ck]               #   列の選択

print('A2 =\n', A2)

A3 = A[ck][:,ck]           #   行と列の選択

print('A3 =\n', A3)

 

実行結果は、以下の通りである。

 

A =

 [[1 2 3]

 [4 5 6]

 [7 8 9]]

ck = [True, False, True]

A1 =

 [[1 2 3]

 [7 8 9]]

A2 =

 [[1 3]

 [4 6]

 [7 9]]

A3 =

 [[1 3]

 [7 9]]

 

 

 

固有分解での応用

 

固有分解のスクリプト例を以下に示す。行列については、拙著「Pythonデータ分析」、「数学入門」、「数学入門」で説明している。

 

import numpy as np

 

a = np.array([[1,2,3],[4,5,6]])

A = a.T @ a

print('A =\n', A)

 

w, v = np.linalg.eigh(A)

print('w =\n', w)

print('v =\n', v)

 

A1 = v @ np.diag(w) @ v.T

print('A1 =\n', A1)

 

実行結果の出力は以下のようである。

 

A =

 [[17 22 27]

 [22 29 36]

 [27 36 45]]

w =

 [-5.29896871e-15  5.97327474e-01  9.04026725e+01]

v =

 [[ 0.40824829 -0.80596391 -0.42866713]

 [-0.81649658 -0.11238241 -0.56630692]

 [ 0.40824829  0.58119908 -0.7039467 ]]

A1 =

 [[17. 22. 27.]

 [22. 29. 36.]

 [27. 36. 45.]]

 

特異値が小さいものから大きいものの順になっているので、これを以下のスクリプトによって大きいものから小さいものへの順に並べ替える。

 

idx = np.argsort(-w)

print('idx =', idx)

 

w = w[idx]

v = v[:,idx]

print('w =\n', w)

print('v =\n', v)

 

A2 = v @ np.diag(w) @ v.T

print('A2 =\n', A2)

 

実行結果の出力は以下のようになる。

 

idx = [2 1 0]

w =

 [ 9.04026725e+01  5.97327474e-01 -5.29896871e-15]

v =

 [[-0.42866713 -0.80596391  0.40824829]

 [-0.56630692 -0.11238241 -0.81649658]

 [-0.7039467   0.58119908  0.40824829]]

A2 =

 [[17. 22. 27.]

 [22. 29. 36.]

 [27. 36. 45.]]

 

特異値の小さいものを除くスクリプト例を以下のように用意した。

 

ckidx = (w > 0.01)

print('ckidx =', ckidx)

w1 = w[ckidx]

v1 = v[:,ckidx]

print('w1 =', w1)

print('v1 =\n', v1)

A3 = v1 @ np.diag(w1) @ v1.T

print('A3 =\n', A3)

 

実行結果の出力は、以下の通りである。

 

ckidx = [ True  True False]

w1 = [90.40267253  0.59732747]

v1 =

 [[-0.42866713 -0.80596391]

 [-0.56630692 -0.11238241]

 [-0.7039467   0.58119908]]

A3 =

 [[17. 22. 27.]

 [22. 29. 36.]

 [27. 36. 45.]]

 

 

 

特異値分解での応用

 

特異値分解のスクリプト例を以下に示す。行列については、拙著「Pythonデータ分析」、「数学入門」、「数学入門」で説明している。

 

import numpy as np

 

A = [[1,2,3,4,5], [5,4,3,2,1],[1,1,1,1,1]]

print('A =\n', A)

u, s, vh = np.linalg.svd(A, full_matrices=False)

print('u =\n', u)

print('s =\n', s)

print('vh =\n', vh)

A1 = u @ np.diag(s) @ vh

print('A1 =\n', A1)

 

実行結果は、以下のような出力になる。

 

A =

 [[1, 2, 3, 4, 5], [5, 4, 3, 2, 1], [1, 1, 1, 1, 1]]

u =

 [[-6.88247202e-01  7.07106781e-01 -1.62221421e-01]

 [-6.88247202e-01 -7.07106781e-01 -1.62221421e-01]

 [-2.29415734e-01 -1.38777878e-16  9.73328527e-01]]

s =

 [9.74679434e+00 4.47213595e+00 3.39845521e-16]

vh =

 [[-4.47213595e-01 -4.47213595e-01 -4.47213595e-01 -4.47213595e-01

  -4.47213595e-01]

 [-6.32455532e-01 -3.16227766e-01 -1.90719178e-16  3.16227766e-01

   6.32455532e-01]

 [ 6.22264954e-01 -7.09529044e-01 -1.61658331e-01 -3.71560229e-02

   2.86078444e-01]]

A1 =

 [[1. 2. 3. 4. 5.]

 [5. 4. 3. 2. 1.]

 [1. 1. 1. 1. 1.]]

 

特異値の小さい部分を除くため、次のスクリプトで特異値の選択リストを作成した。

 

idx = s > 0.01

print('idx =', idx)

 

実行結果の出力は以下のようである。

 

idx = [ True  True False]

 

このidxにより選択を行うスクリプトを以下のように用意した。

 

u1 = u[:, idx]              #   列の選択

s1 = s[idx]

vh1 = vh[idx]               #   行の選択

print('u1 =\n', u1)

print('s1 =', s1)

print('vh1 =\n', vh1)

A2 = u1 @ np.diag(s1) @ vh1

print('A2 =\n', A2)

 

実行結果の出力は、以下のようである。

 

u1 =

 [[-6.88247202e-01  7.07106781e-01]

 [-6.88247202e-01 -7.07106781e-01]

 [-2.29415734e-01 -1.38777878e-16]]

s1 = [9.74679434 4.47213595]

vh1 =

 [[-4.47213595e-01 -4.47213595e-01 -4.47213595e-01 -4.47213595e-01

  -4.47213595e-01]

 [-6.32455532e-01 -3.16227766e-01 -1.90719178e-16  3.16227766e-01

   6.32455532e-01]]

A2 =

 [[1. 2. 3. 4. 5.]

 [5. 4. 3. 2. 1.]

 [1. 1. 1. 1. 1.]]

 

 

 

Home