【Python】沖縄のリゾートホテルのクチコミをテキストマイニングしてみた。

# きっかけ
こんにちは、今回は沖縄のリゾートホテルのクチコミをテキストマイニングで可視化したいと思います。
沖縄が大好きでよくバケーションで訪れますが、どのホテルを予約しようか迷いますよね。。
今回はよく利用するホテルのクチコミをテキストマイニングし、どんなポイントが高評価なのか探りたいと思います。そして、比較としてビジネスホテルのクチコミも見ていきます。

# クチコミサイトのスクレイピング
スクレイピングの方法は下記ページを参考にしました。
https://axross-recipe.com/recipes/518
ホテルのクチコミはじゃらんから引っ張ってきました。どのホテルかは特定を避けるために消しておきます。
対象としたホテル
・リゾートホテル：沖縄県西海岸にあるハイクラスホテル　クチコミ評価★4.7
・ビジネスホテル：沖縄県南部にある格安ホテル　クチコミ評価★3.7

```Python
#スクレイピング可能か確認
import requests
import urllib.robotparser

# スクレイピング対象のページのURL
load_url = "お好きなホテルのクチコミのURL"

# robots.txtのURL
robots_url = "https://www.jalan.net/robots.txt"

# robots.txtの読み取り
rp = urllib.robotparser.RobotFileParser()
rp.set_url(robots_url)
rp.read()

# 対象のページがrobots.txtで禁止されているか調べる
user_agent = '*'
result = rp.can_fetch(user_agent, load_url) # True：許可、False：禁止
```
resultの出力がTrueでしたのでスクレイピングOKでした。
続いて、ページ内のすべてのクチコミを取得し、性別・年代・評価別でみていきます。

```Python
# ページ内のすべてのクチコミを取得
kuchikomis = soup.find_all("div", class_="jlnpc-kuchikomiCassette")

for kuchikomi in kuchikomis:
    gender_age = kuchikomi.find("span", class_="c-label").text.strip() # 性別/年代
    rating = kuchikomi.find("div", class_="jlnpc-kuchikomiCassette__totalRate").text # 評価
    review = kuchikomi.find("p", class_="jlnpc-kuchikomiCassette__postBody").text # クチコミ内容
    print(gender_age, rating, review)
```
データフレームに格納します。
```Python
#データフレームに格納
import pandas as pd

# クチコミを取り出してDataFrameの形式にする
# 空のDataFrameを作る
df = pd.DataFrame(columns=['クチコミ内容','性別/年代','評価',])

# ページ内のすべてのクチコミを取得
kuchikomis = soup.find_all("div", class_="jlnpc-kuchikomiCassette")

for kuchikomi in kuchikomis:
    gender_age = kuchikomi.find("span", class_="c-label").text.strip() # 性別/年代
    rating = kuchikomi.find("div", class_="jlnpc-kuchikomiCassette__totalRate").text # 評価
    review = kuchikomi.find("p", class_="jlnpc-kuchikomiCassette__postBody").text # クチコミ内容
    # DataFrameにデータを追加する
    df = df.append({'クチコミ内容': review,'性別/年代': gender_age, '評価': rating, }, ignore_index=True)

# DataFrameを表示する
display(df)
```
こんな感じでクチコミを取得できました！
![df.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2874461/816e861e-448b-2bb8-428c-85040c7618f6.png)
csv保存しておきます。

```Python
df.to_csv("kuchikomi.csv", index=True)
```
# クチコミのテキストマイニング
便利なツールUserLocalを使ってテキストマイニングしていきます！
https://textmining.userlocal.jp/

## ワードクラウドの作成
みんな大好きワードクラウド！ということで、クチコミのワードクラウドを作成します。
![wordcloudまとめ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2874461/0393d568-c96b-9c5b-05ef-c52050ebd735.png)

リゾートホテルは「朝食、レストラン、海、プール」といったワードが目立ち、これらが評価されていることが分かります。
一方、ビジネスホテルは「便利、駅、立地」といった利便性が評価されています。

## 口コミ評価の比較
続いて口コミ評価の★の数を比較します。
```Python
# グラフに日本語を表示するにはjapanize_matplotlibというモジュールが必要です
# あらかじめ pip install japanize-matplotlib コマンドでインストールしておいてください
import japanize_matplotlib
import matplotlib.pyplot as plt

# '評価'列の型をintに変更
df = df.astype({'評価':int})

# 集計
df_count = df.groupby('評価').count()

# グラフを描画する
df_count[['性別/年代']].plot.bar()

plt.savefig("review_kafu.png")   # プロットしたグラフをファイルsin.pngに保存する
plt.show()
```
![クチコミ評価.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2874461/2fe843e8-a234-fd3a-458a-c3fd3753b38d.png)

リゾートホテルは★4と5のみの高評価！ビジネスホテルは1~5まで分かれていました。

## 係り受け表現の可視化
次は、クチコミのコメント内の名詞を形容詞をピックアップし、それぞれがどのように係っているか可視化しました。
![係り受け表現まとめ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2874461/e5f5aaef-5e89-b681-9272-ee164ad97cfb.png)
リゾートホテルは「部屋-広い」、「朝食-美味しい」、「綺麗-良い」、「部屋-過ごしやすい」というコメントがあることが分かりました。
ビジネスホテルは「駅-近い」、「風呂-広い」、「場所-分かりにくい」、「利便性-高い」という駅に近いことは評価されつつも、場所がわかりにくいといった少しネガティブなコメントもあることが分かりました。

## 対応分析結果
最後に、それぞれの評価ごとにどんなコメントが対応しているのか見ていきます。こちらはKH-coderで作成しました。KH-coderの使い方は下記で詳説されています。
https://toukeier.hatenablog.com/entry/correspondence-analysis-of-text-data-in-KH-coder
![対応分析まとめ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2874461/dd275597-94ac-4337-feed-c6715377d720.png)

対応分析の結果、リゾートホテルでは「朝食、景色のきれいさ、部屋の広さ」が高評価に繋がっていることが分かりました。
一方、ビジネスホテルは「ベッドの狭さ、部屋の古さ」等が低評価のコメントにあり、「値段や便利さ」は比較的高評価になっていることが分かりました。

# まとめ
Pythonでクチコミサイトのレビューをスクレイピングし、UserLocalとKH-coderを使ってテキストマイニングしました。
その結果、高評価に繋がっている点、低評価になってしまっている点を可視化することができました。
このような簡単な分析を応用することで、競合分析などに使えそうですね！