統計と機械学習

クラスタリング時の標準化の影響

統計と機械学習

[PR]当サイトはアフィリエイト広告を利用しています。

以前k-means法でクラスタリングを試したのですが、入力データを標準化せずに実施したので今回は標準化してやってみます。

参考にしたのは以下の書籍。

須藤秋良(2020)『スッキリわかる Pythonによる機械学習入門』インプレス.

まずは以下のデータをやってみます。

勉強時間国語英語社会数学理科
38890836065
2.58380757071
2.36065708588
2.65560658079
2.48890816570
3.28895927080
2.98083789892
38283799395
16766556770
1.37060706459

プログラムは以下。

#scikit-learn v0.24.0
#Copyright (c) 2007 - 2020 scikit-learn developers.
#Released under the BSD 3-Clause License
#https://github.com/scikit-learn/scikit-learn/blob/main/COPYING

#NumPy v1.19.1
#Copyright (c) 2005-2020, NumPy Developers.
#Released under the BSD 3-Clause License
#https://numpy.org/doc/stable/license.html

import numpy as np
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
#[勉強時間,国語,英語,社会,数学,理科]
data = [[3.0, 88,90,83,60,65],\
        [2.5, 83,80,75,70,71],\
        [2.3, 60,65,70,85,88],\
        [2.6, 55,60,65,80,79],\
        [2.4, 88,90,81,65,70],\
        [3.2, 88,95,92,70,80],\
        [2.9, 80,83,78,98,92],\
        [3.0, 82,83,79,93,95],\
        [1.0, 67,66,55,67,70],\
        [1.3, 70,60,70,64,59]]
data = np.array(data)
scM = StandardScaler()
scM.fit(data)
scX = scM.transform(data)
nc = 5
kmeans = KMeans(n_clusters=nc,).fit(scX)
labels = kmeans.labels_
print(labels)
for i in range(nc):
    print('label:',i)
    for j in range(len(data)):
        if(labels[j] == i):
            print(data[j])

標準化する処理が26行目から28行目に追加されています。

出力は以下。

[4 4 1 1 4 0 2 2 3 3]

label: 0

[ 3.2 88. 95. 92. 70. 80. ]

label: 1

[ 2.3 60. 65. 70. 85. 88. ]

[ 2.6 55. 60. 65. 80. 79. ]

label: 2

[ 2.9 80. 83. 78. 98. 92. ]

[ 3. 82. 83. 79. 93. 95.]

label: 3

[ 1. 67. 66. 55. 67. 70.]

[ 1.3 70. 60. 70. 64. 59. ]

label: 4

[ 3. 88. 90. 83. 60. 65.]

[ 2.5 83. 80. 75. 70. 71. ]

[ 2.4 88. 90. 81. 65. 70. ]

これは前回のグループ分けとおなじ結果になりました。

次は前回の記事の2問目の問題をクラスタリングしてみます。

プログラムは以下。

#scikit-learn v0.24.0
#Copyright (c) 2007 - 2020 scikit-learn developers.
#Released under the BSD 3-Clause License
#https://github.com/scikit-learn/scikit-learn/blob/main/COPYING

#NumPy v1.19.1
#Copyright (c) 2005-2020, NumPy Developers.
#Released under the BSD 3-Clause License
#https://numpy.org/doc/stable/license.html

import numpy as np
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
#[読解力,計算力,スピード,正答率%]
data = [[4,3,4,73],\
        [3,5,5,60],\
        [5,3,3,55],\
        [2,4,4,78],\
        [3,4,4,70],\
        [3,4,4,62],\
        [5,2,3,56],\
        [1,4,3,75]]
data = np.array(data)
scM = StandardScaler()
scM.fit(data)
scX = scM.transform(data)
nc = 4
kmeans = KMeans(n_clusters=nc,).fit(scX)
labels = kmeans.labels_
print(labels)
for i in range(nc):
    print('label:',i)
    for j in range(len(data)):
        if(labels[j] == i):
            print(data[j])

出力は以下。

[3 0 1 2 3 3 1 2]

label: 0

[ 3 5 5 60]

label: 1

[ 5 3 3 55]

[ 5 2 3 56]

label: 2

[ 2 4 4 78]

[ 1 4 3 75]

label: 3

[ 4 3 4 73]

[ 3 4 4 70]

[ 3 4 4 62]

前回の出力は以下。

[3 0 2 1 3 0 2 1]

label: 0

[ 3 5 5 60]

[ 3 4 4 62]

label: 1

[ 2 4 4 78]

[ 1 4 3 75]

label: 2

[ 5 3 3 55]

[ 5 2 3 56]

label: 3

[ 4 3 4 73]

[ 3 4 4 70]

データ[ 3 4 4 62]が違うグループに分類されました。

最初の問題と2問目で何か違うのか考えてみたのですが、1問目は点数がメインで2桁のデータが5つ、1桁のデータが1つだったので、2桁のデータの違いが際立って、1桁のデータの違いはあまり影響を及ぼさなかったと考えられます。

標準化することで各変数の影響度は同じくらいになりましたが、5つのデータに対して1つのデータですから、5つのデータの影響度はやはり高いままで、結果に影響はなかったようです。

2問目では2桁が1つ、1桁が3つなのですが、2桁のデータの差が1桁のデータの差に対して大きいので、ここの影響度が前回の記事の分析では多く反映されたと思われます。2桁のデータの差があまりないから前回はグループ0に分類されたようです。差が大きいとデータ間の距離が遠くなって違うグループに分類されます。

しかし標準化によって各変数の影響度が同じくらいになったので、変数の数が多い1桁のデータの影響度が増したようです。1桁のデータで差がないというグループ分けがなされたようです。今回の分析でのグループ3は2桁の変数の差が大きいのに[ 3 4 4 62]がここに分類されているのはそのためでしょう。

標準化すると各変数間の影響度が同じくらいになるということが確認できました。

どの変数も影響すると考えるなら標準化したほうが良いでしょう。