~複数の評価尺度で点数づけされたデータをシンプルにしたり、グルーピングしたりする(Pythonによる特異値分解とクラスタリング分析)~
はじめに
Pythonでデータ分析・・・私にとってはマダマダ夢物語に近いが、そんな状況の私でも「見よう見まねでできるようにはなるかも?!」という気にさせてくれるのが、『データサイエンス塾!!』さんだ。
多くの動画をアップしておられるが、再生リストのなかに「とてもよくわかる機械学習の基本」(全11の動画)というタイトルの再生リストがあり、
同じデータが扱われている動画#1~#3について、私が倣って実施した備忘として記録するもの。
実行条件など
・Google colabで実行
・一部のコードだけ変更させていただいています
※あるグラフをseaborn+層別で描きたかった等によるものです。データサイエンス塾!!さん、すいません。
概要説明
私たちは「いくつかの尺度をあげ、対象候補を比較する」ということを日常的に行っています。
- 携帯電話なら、尺度は『サイズ,容量,機能,…』等となり、対象候補はA社,B社…。
- 店舗なら、尺度は『サービス,立地,品揃え,…』等となり、対象候補はA店,B店…。
尺度、対象候補ともに限られたデータ数の場合は把握できそうですが、データ数が多くなると簡単ではありません。
① 尺度が多い場合は、限られた要素にギュッとまとめて表現できるとよいし、
② 対象候補が多い場合は、限られたグループに分けられるといいですね。
上記①②のようなケースでは、以下の手法が利用されます。
① 尺度をギュッとまとめる ⇒ SVD(特異値分解)という手法を利用
② 対象候補を限られたグループに分ける ⇒ k-means法 及び クラスター分析を利用
この記事では、
k-means法でグループ分けを行い ⇒ SVD(特異値分解)で尺度を単純化 ⇒ その後、k-means法とSVDの合わせ技の分析結果 を行い、最後にクラスター分析も行います。
「とてもよくわかる機械学習の基本(動画#1~#3)」の例題について
例題は「人のスキル」データとされています。
尺度は『コミュニケーション,リーダーシップ,プログラミング,ネットワーク知識,セキュリティ知識』、対象候補はAさん~Oさん(全15名)。
データ分析により、よりシンプルな尺度で、対象候補をいくつかのグループに分けることができ、その結果、”「人のスキル」全体を眺めるとこんな傾向があるといえるね!” などといえる・・・が目指したいゴールとなります。
ライブラリのインストールおよびインポート
Google colabでグラフ描画すると、日本語が文字化けするので、まず以下をインストール。
※文字化けしない方は無視していい
pip install japanize-matplotlib
ライブラリのインポート。私はどのライブラリが必要かを逐次判断するのは面倒なので、基本以下をデフォルトでインポートしています。(雑ですいません)
# Import required libraries
%matplotlib inline
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
import seaborn as sns
sns.set(font="IPAexGothic")
from scipy.stats import norm
データの読み込み
- 例題ファイル(CSV)をダウンロードし、Google colabにアップロード
※Google Colabへのアップロードの方法はここでは述べません。
- CSVファイルの読み込み。
以下コードの実行により、「df」というデータフレームにcsvデータが納められます。
# csvファイル読込み(indexとして使いたい列の列番号がある場合は指定:今回は index_col=0)
Path = 'https://analysis-navi.com/wp-content/uploads/2021/07/4-2_skill_level.csv'
df = pd.read_csv(Path, index_col=0)
k-meansの実行
k-meansは、k平均法と呼ばれるクラスタリング手法のひとつです。
読込んだデータは、対象候補 Aさん~Oさん(全15名)のスキル(コミュニケーション,リーダーシップ,プログラミング,ネットワーク知識,セキュリティ知識)が10段階数値で示されたデータです。
「クラスタ数(いくつのグループに分けたいか?)」を設定し、以下のコード実行するだけで、対象候補 Aさん~Oさん(全15名)を設定したグループ数に分けてくれます。
# k-means実行
from sklearn.cluster import KMeans
# クラスター数を任意に指定する
vec = KMeans(n_clusters=4)
group_num = vec.fit_predict(df)
分けられたグループが「group_num」というデータフレームに入ったかを見てみます。
# グループ分けの結果(k-meansは計算の度に結果変わる)
group_num
出力結果
array([3, 2, 1, 3, 0, 3, 2, 3, 1, 2, 1, 0, 1, 1, 0], dtype=int32)グラフ化などを進めるため、上記グループ分けの結果をデータフレームに反映する処理を行います。
まずは、新たにデータフレーム「df_calc」を用意し、
# df_calcというデータフレームにdfをコピー
df_calc = df.copy()
次に、「df_calc」にグループ分けの結果「group_num」を反映します。
# df_calcに['グループ名']を追加し、group_numのデータを登録
df_calc['グループ名'] = group_num
df_calc
データ傾向を見てみる
平均値
グループ毎の集計が可能となったので、グループ毎の平均値を算出します。
#グループ毎に平均値を出す
df_calc.groupby('グループ名').mean()
散布図行列
グループ分けした傾向を散布図行列(ペアプロット)で眺めるということを実行されていたサイトがありましたので、同様にやってみました。ただ、これは参考程度かと思います。
sns.pairplot(data=df_calc,hue="グループ名",palette='Blues')
SVD(特異値分解)の実行
以下のコードでSVD(特異値分解)が実行できます。
from sklearn.decomposition import TruncatedSVD
model_svd = TruncatedSVD(n_components=2)
vecs_list = model_svd.fit_transform(df)
配置された座標を確認してみます。
vecs_list
# 評価尺度を平面に配置(※X軸,Y軸がどのような軸かは人が読み取らないといけない)
X_comp,Y_comp = model_svd.components_
plt.figure(figsize=(6,6))
sns.scatterplot(x=X_comp,y=Y_comp)
plt.title('SVD', fontsize=18) # グラフタイトル
for i,(annot_x,annot_y) in enumerate(zip(X_comp,Y_comp)):
plt.annotate(df.columns[i],(annot_x,annot_y))
以下の通り、平面上に「尺度」が配置されました。
例えば、右方向「スキルレベル」、上方向「ヒューマンスキル」、下方向「ITスキル」となるな・・・等、これは人が読み取って名付けるしかありません。
今度は、各サンプル(Aさん~Oさん)を平面座標に配置する手続きになります。
この座標「vecs_list」を元のデータフレーム(df_calc)に結合します。
# df_calcに['X']['Y']列を追加、それぞれにvecs_listの0列目と1列目データを登録
df_calc['X'] = vecs_list[:,0]
df_calc['Y'] = vecs_list[:,1]
結合した結果を見てみます。
# df_calcへのX,Yデータ追加を確認
df_calc
グループ化した結果を平面上に可視化
最後に、SVDで尺度を要約した(平面座標X,Y)に、k-meansでグループ分けしたサンプル(Aさん~Oさん)を配置します。
# SVD(特異値分解)した平面にk-meansでクラスター分け(グループ名)したサンプルをグラフに配置
plt.figure(figsize=(6,6))
sns.scatterplot(data=df_calc,x='X',y='Y',hue="グループ名")
plt.title('k-means + SVD', fontsize=18) # グラフタイトル
for i,(x_name,y_name) in enumerate(zip(df_calc['X'],df_calc['Y'])):
plt.annotate(df.index[i],(x_name,y_name))
plt.show()
以下が配置の結果です。
グループ0は中央下に、グループ1は右下に、グループ2に右上に、グループ4は左下に配置されています。
軸の意味合いは、右方向「スキルレベル」、上方向「ヒューマンスキル」、下方向「ITスキル」ということでしたので、『グループ1はスキルレベルが高く、特にヒューマンスキルが顕著』、『グループ2もスキルレベルが高く、特にITスキルが顕著』・・・等、グループの特徴の違い、各グループにどのサンプルが属すか?等が把握できます。
クラスター分析
例題データの尺度の単純化とグループ分けは、上記までの流れで一旦完了。
SVDで尺度を単純化、k-meansでグループ分け・・・という内容でしたが、グループ分けの方法は以下に示す「クラスター分析」による方法もあります。
分析の結果、出力される「デンドログラム(樹形図)」をみるとわかりますが、サンプルがトーナメント表のような形で表現されます。
似たサンプルほど近くに配置されるのは、k-meansと同じですが、平面に打点されるk-meansよりもデンドログラムの方がサンプル間の関係がより細かく把握できるという特徴があります。
データサイエンス塾!!さん曰く、サンプル数が少ない場合はクラスター分析=デンドログラムでもよいが、サンプルが多い場合は(デンドログラムは見にくくなるので)k-meansのほうがよいとのことでした。
# クラスター分析実行(methodでクラスター分析手法[ward法が一般]、metricで分類に用いる対象間の距離計算方法を指定[euclidean=ユークリッド距離])
from scipy.cluster.hierarchy import linkage,dendrogram,fcluster
linkage_result = linkage(df, method = "ward", metric = "euclidean")
linkage_result
# デンドログラムの描画
dendrogram(linkage_result, labels = df.index)
plt.show()
最後に
Pythonで、データを読込み、グラフ表示・・・くらいのことしかできなかった私に希望を与えてくれたのは、まちがいなくデータサイエンス塾!!さんです。
マダマダ自力で何とかできるレベルではないことは自覚していますが、なんかできそうな気にさせていただいた。
あたらめて感謝いたします。
参考サイト