1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ホテルの評価値の次元削減をする

Posted at

はじめに

本記事では、Pythonで特異値分解を行い、ホテルの評価値データの次元削減を行います。使用するデータは以前紹介した記事Pythonでじゃらんの口コミをスクレイピングするで取得したものになります。

環境

python 3.10.4
Windows 11 Home

次元削減とは

教師なし学習の1つで、多次元のデータをなるべく情報を失わないように低次元のデータに変換することです。データを要約して全体像を分かりやすくことができます。今回使用する特異値分解はこの次元削減の手法の1つになります。

データの構造

今回使うデータは以下のような構造になっています。

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項目を次元削減し、2次元に変換します。

使用するライブラリ

使用するライブラリは以下の4つです。

pip install pandas
pip install matplotlib
pip install scikit-learn
pip install seaborn

作成コード

作成したコードは以下になります。

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import TruncatedSVD
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_)

    make_item_info(model_svd, df)
    make_scatter(vecs_list)

#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

#評価尺度の散布図を作成する
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()

#2次元に変換したデータで散布図を作成する
def make_scatter(vecs_list):
    X = vecs_list[:,0]
    Y = vecs_list[:,1]

    plt.figure(figsize=(10,10))
    sns.set()
    sns.scatterplot(x=X,y=Y)
    plt.show()    

if __name__ == "__main__":
    main()

解説

特異値分解を行う

model_svd = TruncatedSVD(n_components=2)
vecs_list = model_svd.fit_transform(df)
  • TruncatedSVD(n_components=n)
    n次元のモデルを作成
  • model_svd.fit_transform(df)
    指定したデータに特異値分解を行い、結果を取得

何次元のデータに変換するかをTruncatedSVD(n_components=n)で指定し、model_svd.fit_transform(df)で指定した次元に変換したデータを取得します。

寄与率を算出する

model_svd.explained_variance_ratio_

寄与率とは、次元削減を実行後、情報がどれくらい残っているかを示す割合です。明確な基準はありませんが、算出した数値の合計(累積寄与率)が60%より低い場合は、分析対象を再検討する方が良いそうです。

評価尺度のグラフを作成する

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()
  • seaborn.scatterplot(x,y)
    散布図を作成
  • for i, (a, b, ...) in enumerate(zip( ... ))
    複数のリストの要素とインデックスを同時に取得するループ
  • pyplot.annotate(表示する文字,{x座標,y座標})
    指定した座標に注釈を表示

どの項目が高いと座標が上にくるのか、どの項目が高いと座標が下にくるのかが分かるグラフを作成します。

実行結果

寄与率

[0.48859845 0.18190892]

第1成分が0.48859845、第2成分が0.18190892、累積寄与率が0.67050737となりました。情報が約67%残っており、60%以上となっているため、使用データに問題はなさそうです。

評価尺度のグラフ

散布図から「料理(朝食)」、「料理(夕食)」の数値が高いと座標が上の方に配置され、「部屋」、「清潔感」、「風呂」の数値が高いと座標が下の方に配置されることが分かります。つまり、食事の満足度の方が高い人は上に、施設の満足度の方が高い人は下に配置されるということになります。

データを2次元に変換した際の散布図

データを2次元に変換し、散布図で表示することができました。上下の偏りがあまりなく、満遍なく座標のある図となりました。なお、横軸は評価値合計の高さ(合計値が高いほど右に位置する)を表します。

終わりに

今回は、ホテルの評価値データを特異値分解し、次元削減を行いました。
次元削減は特異値分解だけではなく、様々な手法があるため、別の手法も試して比較してみるのも面白そうだなと思いました。
次回は、同じデータを使ってクラスタリングを試してみる予定です。

参考

この記事は以下の動画を参考にして執筆しました。
Pythonで次元削減(次元圧縮)してみよう【Python機械学習#1】

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?