ロード・トゥ・ザ・ホワイトハッカー

ホワイトハッカーはじめました

アンケート分析(4):クラスタリング

クラスタ分析

クラスタリングクラスタ解析など呼ばれますが、データを一定のグループにまとめること。階層型と非階層型がある。

 

アンケート結果に対してクラスタ分析を行うことで、いくつかの傾向を読み取り、それに対してアクションを取ることを可能にしたい。

 

以下のサイトを参考にさせていただきました。

というか、ほぼコード流用です。

yyhhyy.hatenablog.com

 
階層型クラスタリング

いくつくらいのグループに分けるのがいいのか、あらかじめ決まっていれば良いですが、ある程度、データからグループ数の参考を得たい。

その際は、樹形図(dendrogram デンドログラム)を使ってビジュアルに表現して、データの概要を把握する。

 

デンドログラムのコード

from scipy.cluster.hierarchy import linkage, dendrogram
import matplotlib.pyplot as plt
import seaborn as sns

#ウォード法を使用

questionnaire_s_hclust = linkage(questionnaire_s,metric="euclidean",method="ward")
plt.figure(figsize=(12,8))
dendrogram(questionnaire_s_hclust)
plt.savefig('figure_1.png')
plt.show()

 

f:id:chikuwamaruX:20210821154244p:plain

4つのグループに分けると、3、6、3、8個に分類される、という参考になる。

 

非階層型クラスタリング

ある程度、クラスタ数が決まれば、k平均法による非階層型クラスターに分割して、分析をすることで、それぞれのクラスタの解釈をする。

k平均法のクラスタリングは、教師無し機械学習、と呼ばれます。

 

実際のコード

k平均法のおまじない

from sklearn.cluster import KMeans

#クラスタ数を4に設定
km = KMeans(n_clusters=4,random_state=42)

 

クラスタリングして、結果を保存

#numpyの行列に変換
questionnaire_arr = questionnaire_s.values
#kmeansを適用した結果のグルーピングの配列が出力として渡される
questionnaire_add_pred = km.fit_predict(questionnaire_arr)
#元のデータにクラスタIDを追加
questionnaire["cluster_ID"] = questionnaire_add_pred

クラスタIDをカテゴリに変更して、集計する。

#カテゴリカル変数に変更
questionnaire["cluster_ID"] = questionnaire["cluster_ID"] .astype("category")
questionnaire["cluster_ID"].value_counts()

 

実際の実行結果

f:id:chikuwamaruX:20210821155633p:plain


8,5,4,3個の4つのグループが出来ました。階層型クラスタリングと結果は異なりますが、ある程度バランスが取れている、ことにしておきます。

 

更なる分析

4つのグループの特徴=回答の偏りがどのあたりにあるのか、を知るために、データを再構成していく。

 

以下により、ダミー変数を使って、クロス集計表のようなものを作成する。

#全ての項目をカテゴリ化
questionnaire = questionnaire[:].astype("category")

#ダミー変数化したい列を指定するために列名を取得してリスト化、更にクラスタIDを除く
dummy_list = list(questionnaire.columns)[0:-1]

#ダミー変数化したい列名を指定して全ての設問をダミー変数化
questionnaire_dmy = pd.get_dummies(questionnaire, columns=dummy_list)

f:id:chikuwamaruX:20210821161223p:plain

 

次に、クラスタ毎で集計する。

クラスタIDでグループ化し数値を集約します
questionnaire_dmy_gp = questionnaire_dmy.groupby("cluster_ID")

#グループ別に各設問の回答者数の合計を出します
questionnaire_dmy_gp_g = questionnaire_dmy_gp.sum().T

 

f:id:chikuwamaruX:20210821161312p:plain

 

少し見やすくしてみる

questionnaire_dmy_gp_g.style.bar(color="#4285F4")

f:id:chikuwamaruX:20210821161427p:plain

Q1に対して、クラスタIDが0、2,3のグループは、1-3で回答しているが、1のグループは4-5で回答している、という違いが見える。

 

クラスタマップの出力

plt.figure(figsize=(12,8))
sns.clustermap(questionnaire_dmy_gp_g,cmap="viridis")
plt.savefig('figure_2.png')
plt.show()

f:id:chikuwamaruX:20210821161949p:plain

なんとなく、分かったような、分からないような。。。