import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
8 k平均法によるクラスタリング
8.1 クラスタリング
クラスタリングは、類似するデータを類似度や距離などの指標を用いていくつかのグループに分割する手法です。クラスタリングでは、分けられたグループのことをクラスタまたはカテゴリと呼びます。
クラスタリングは顧客を購買履歴などから類似する顧客に分類する顧客セグメンテーション、類似の内容を含む文書を分類するテキストマイニングや、類似の画像を分類する画像認識など、様々な分野で利用されています。また、正常なデータと異常なデータを分類する異常検知にも利用されます。
クラスタリングはデータを自動的に分類する
各クラスタの名前づけは人間が行う
クラスタリングは機械学習の分野では、データがどのグループ(例えば動物の種名や分類群)に属するかという情報を与えず、それ以外の情報を用いて学習することから教師なし学習の一つとして扱われます。クラスタリングの手法はいくつかありますが、ここではk平均法を紹介します。
8.2 k平均法 (k-means法)
k平均法は、データを任意のk個のクラスタに分割する手法です。k平均法は、以下の手順でクラスタリングを行います。
- データをk個のクラスタにランダムに分割する
- 各クラスタの重心を計算する
- 各データを最も近い重心を持つクラスタに再分割する
- 2, 3を繰り返す
- クラスタの再分割が行われなくなったら終了
k平均法を用いてペンギンデータをクラスタリングしてみましょう。
# データの読み込み
= sns.load_dataset("penguins")
penguins
# データの確認
penguins.head()
species | island | bill_length_mm | bill_depth_mm | flipper_length_mm | body_mass_g | sex | |
---|---|---|---|---|---|---|---|
0 | Adelie | Torgersen | 39.1 | 18.7 | 181.0 | 3750.0 | Male |
1 | Adelie | Torgersen | 39.5 | 17.4 | 186.0 | 3800.0 | Female |
2 | Adelie | Torgersen | 40.3 | 18.0 | 195.0 | 3250.0 | Female |
3 | Adelie | Torgersen | NaN | NaN | NaN | NaN | NaN |
4 | Adelie | Torgersen | 36.7 | 19.3 | 193.0 | 3450.0 | Female |
データ上にはspecies
列が存在するので、ペンギンの身体の部位の大きさや体重、生息地の情報から
# データの前処理
# 欠損値を含む行の削除
= penguins.dropna()
penguins
from sklearn.preprocessing import LabelEncoder
= LabelEncoder()
le "species"] = le.fit_transform(penguins["species"])
penguins[
# データの分割
= penguins.drop(columns=["species", "island", "sex"]) # speciesを含め、数値を含まない列を削除
X = penguins["species"]
y
# データの標準化
= StandardScaler()
scaler = scaler.fit_transform(X) X_std
# k平均法の実行
= KMeans(n_clusters=3, random_state=0)
kmeans kmeans.fit(X_std)
KMeans(n_clusters=3, random_state=0)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
KMeans(n_clusters=3, random_state=0)
kの数はいくつにするのがよい?
エルボー法は古い?
8.2.1 結果の確認と比較
データがどのように分類されたか、元のデータと比較して確認してみましょう。
# クラスタリング結果の確認
# クラスタリング結果のラベル
= kmeans.labels_
labels labels
array([2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0,
2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2,
2, 0, 2, 0, 2, 2, 2, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2,
2, 0, 2, 2, 2, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 0, 2, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0,
2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1], dtype=int32)
==np.array(y)).sum() / len(labels) (labels
0.06606606606606606
# Xにラベルを追加
"cluster"] = np.where(labels == 1, 2, np.where(labels == 2, 1, labels))
X[
# クラスタリング結果のプロット
# bill_length vs bill_depth
=X, x="bill_length_mm", y="bill_depth_mm", hue="cluster")
sns.scatterplot(data
plt.show()
=penguins, x="bill_length_mm", y="bill_depth_mm", hue="species")
sns.scatterplot(data plt.show()
不一致のデータを確認してみましょう。
# 不一致のデータを確認
# sns.scatterplotに追加
=X[labels == np.array(y)], x="bill_length_mm", y="bill_depth_mm", hue="cluster")
sns.scatterplot(data# 不一致のデータを追加
=X[labels != np.array(y)], x="bill_length_mm", y="bill_depth_mm", hue="cluster") sns.scatterplot(data