はじめに
本記事では、Pythonでk-means法を実行し、ホテルの評価データをクラスタリングします。使用するデータは以前紹介した記事Pythonでじゃらんの口コミをスクレイピングするで取得したものになります。
環境
python 3.10.4
Windows 11 Home
k-means法とは
非階層型クラスタリング手法で、以下の手順でデータをk個に分類します。
① 各データに対してランダムにクラスタを割り振る
② 各クラスタの重心を計算する
③ 各データに対して最も近いクラスタを再度割り振る
④ ②と③をクラスタに変化が出なくなるまで繰り返す
※クラスタ数kは事前に人間が指定する
使用するデータの構造
今回使うデータは以下のような構造になっています。
index | 部屋 | 風呂 | 料理(朝食) | 料理(夕食) | 接客・サービス | 清潔感 | 見出し | 本文 |
---|---|---|---|---|---|---|---|---|
0 | 4 | 5 | 5 | 4 | 4 | 4 | 見出し1 | 本文1 |
1 | 3 | 4 | - | 5 | 4 | 5 | 見出し2 | 本文2 |
2 | 4 | 3 | 5 | 4 | 4 | 3 | 見出し3 | 本文3 |
以降データが続く |
5段階評価の「部屋」、「風呂」、「料理(朝食)」、「料理(夕食)」、「接客・サービス」、「清潔感」の6項目にk-means法を用いてクラスタリングします。
使用するライブラリ
使用するライブラリは以下の4つです。
pip install pandas
pip install matplotlib
pip install scikit-learn
pip install seaborn
クラスタリングを行う
csvを読み込み、4つのクラスタに分類後、csvで出力します。
※計算の都合上、実行の度、クラスタ番号や結果が変化します
作成コード
import pandas as pd
from sklearn.cluster import KMeans
df = pd.read_csv("箱根湯本温泉_ホテル南風荘.csv", index_col=0)
#不要な列の削除
df = df.drop(["見出し","本文"], axis=1)
#未回答を中間値の3に置換する
df = df.replace("-","3")
#k-meansで4つのクラスタに分類する
vec = KMeans(n_clusters=4)
group_num = vec.fit_predict(df)
#クラスタ番号をdataframeに追加し、csvで出力する
df["クラスタ番号"] = group_num
df.to_csv("クラスタ番号付きデータ.csv", encoding="utf-8")
結果
index | 部屋 | 風呂 | 料理(朝食) | 料理(夕食) | 接客・サービス | 清潔感 | クラスタ番号 |
---|---|---|---|---|---|---|---|
0 | 4 | 5 | 5 | 4 | 4 | 4 | 3 |
1 | 3 | 4 | 3 | 5 | 4 | 5 | 1 |
2 | 4 | 3 | 5 | 4 | 4 | 3 | 0 |
以降データが続く |
n_clusters
を4に設定したので「クラスタ番号」は0~3のいずれかになります。
次元削減と組み合わせる
次元削減と組み合わせて、クラスタリングした結果を散布図に描画します。次元削減については前回の記事「ホテルの評価値の次元削減をする」をご参照ください。
作成コード
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import TruncatedSVD
from sklearn.cluster import KMeans
import seaborn as sns
def main():
df = make_df()
#2次元に変換する
model_svd = TruncatedSVD(n_components=2)
vecs_list = model_svd.fit_transform(df)
#寄与率を算出する
print(model_svd.explained_variance_ratio_)
cluster_num = run_kmeans(df)
make_item_info(model_svd, df)
make_scatter(vecs_list, cluster_num)
#csvを読み込んでdataframeを作成する
def make_df():
df = pd.read_csv("箱根湯本温泉_ホテル南風荘.csv", index_col=0)
#不要な列の削除
df = df.drop(["見出し","本文"], axis=1)
#未回答を中間値の3に置換する
df = df.replace("-","3")
return df
#k-meansで4つのクラスタに分類する
def run_kmeans(df):
vec = KMeans(n_clusters=4)
cluster_num = vec.fit_predict(df)
add_cluster_df = df.copy()
add_cluster_df["クラスタ番号"] = cluster_num
add_cluster_df.to_csv("クラスタ番号付きデータ.csv", encoding="utf-8")
return cluster_num
#評価尺度の図を作成する
def make_item_info(model_svd, df):
X_comp,Y_comp = model_svd.components_
plt.figure(figsize=(10,10))
sns.set(font="MS Gothic")
sns.scatterplot(x=X_comp,y=Y_comp)
for i,(annot_x,annot_y) in enumerate(zip(X_comp,Y_comp)):
plt.annotate(df.columns[i],{annot_x,annot_y})
plt.show()
#散布図を作成する
def make_scatter(vecs_list, cluster_num):
X = vecs_list[:,0]
Y = vecs_list[:,1]
#クラスタ番号を色で対応付ける
color_codes = {0:"red", 1:"blue", 2:"green", 3:"yellow"}
colors = [color_codes[x] for x in cluster_num]
plt.figure(figsize=(10,10))
sns.set()
sns.scatterplot(x=X, y=Y, color=colors)
plt.show()
if __name__ == "__main__":
main()
実行結果
寄与率
[0.48859845 0.18190892]
評価尺度のグラフ
次元削減とk-means法を適用した散布図
以下のようにクラスタリングされました。
赤:食事、施設ともに満足度が高いクラスタ
青:食事の満足度は高いが施設の満足度が低いクラスタ
緑:施設の満足度は高いが食事の満足度が低いクラスタ
黄色:食事、施設ともに満足度が低いクラスタ
若干、青や緑のクラスタ付近に黄色の点が混じっていますが、概ね評価ごとのクラスタリングに成功しました。
精度が怪しい場合は、KMeans(n_clusters=4, max_iter=500)
等、max_iter
(重心の計算回数)を増やすと良いそうです。(デフォルトは300)
終わりに
今回は、k-means法でホテルの評価をクラスタリングしました。
次元削減とクラスタリングを行い、クラスタ特性を理解した後に、口コミのテキストマイニングを行ったり、アンケートを取ったりすることで、好評の理由や改善点がさらに調べられそうと思いました。
参考
この記事は以下の動画・記事を参考にして執筆しました。
・PythonでK-meansクラスタリングしてみよう【Python機械学習#2】
・k-means 法 – 【AI・機械学習用語集】 - zero to one