ぴよ猫ちゃんの機械学習

AI、人工知能、機械学習について色々記事にしています。

AIが商品を厳選!!WatsonのToneAnalyzerで口コミを評価してみた

口コミ評価 WatsonのToneAnalyzerで口コミを評価してみたよ
口コミ評価 やり方を詳しく紹介しますー💛

1.何故AIで口コミ評価をしたか?

AIで口コミ評価をしようとした理由

結論から先に申すと、多数の候補から本当に良い商品を見つけたかったので、AIで口コミ評価が出来るかを試してみました。

商品の良し悪しを買う前に確認する方法

  • 商品比較サイトで最初に見るポイントは値段・機能/特徴・星の数では無いでしょうか?
  • 大体同じ値段で機能も似ていたらどれが良いか判断に迷うので、他の人がどう評価しているかを確認するために星の数を確認しませんか?
  • 商品を買った人から意見を聞くのは商品を選ぶ有効な方法だと思います。
  • 星の数では無く口コミを見た方がより詳細な意見を聞くことが出来ますが、一つ一つの口コミを見ていくのは時間がかかります
  • 短時間でその商品を他の人がどう思っているかを確認するのに星の数を見ることは有効な手段です。

星の数で評価する方法の弱点

  • 星の数は過去にその商品を買った人が付けているので、ある程度信憑性があります。
  • しかし、過去にその商品を買った人は適切に星を付けるでしょうか?
  • 星は自発的につける場合もありますが、その商品を買った時にアンケートを聞かれて受動的に付ける場合もあります。
  • そういった場合、相当な不満が無ければ星3とか4という無難な星を付けませんか?
  • そう、星を付けている人はあまり真剣にその商品を評価していない場合もあります。
  • そういう意味で、星の数は本当に妥当な評価では無い可能性もあります。

星よりも正しく商品を評価する方法

  • では星よりも正確に商品の評価を知るにはどうすれば良いでしょうか?
  • 答えてとしては口コミを見る方が星の数を見るよりも、商品の評価を知ることが出来ます。
  • 口コミを書くということは星を付けることより全然手間のかかる作業です。
  • そういった手間なことをしているということは、口コミを書く人は星を付けるよりも真剣に商品の良さ(もしくは悪さ)を他の人に知って欲しいと考えているということでしょう。
  • ですので口コミを見るのが商品の評価を知るには星の数を見るより有効と言えます。

口コミを読むのは大変

  • 口コミは場合によっては1,000件を超える口コミがある場合もあります。
  • それを一つ一つ読んでいたら大変です。
  • 大変な作業は機械に任せられるなら任せた方が楽です。
  • 最近のAIは優秀で文章の内容がポジティブな文章かネガティブな文章かを判断することが出来ます。
  • なので、このAIの文章判定機能を用いて手間のかかる口コミの分析が出来るかを試してみることにしました。
  • 補足ですが、口コミも星と同じで適当な回答をしている場合がありますが、そういうものはAIが無視する様に出来るのも口コミを評価することのメリットです
    (星の数は適当につけたものか判断できないが、口コミはある程度判断が出来る。)

2.AI(Tone Analyzer)で口コミを評価する方法

IBM WatsonのTone Analyzerとは

IBM WatsonのTone Analyzerは、言語分析を使用して、記述されたテキストから感情トーンと言語トーンを検出するAIサービスです。
このサービスは、ドキュメント(文章全体)とセンテンス(文節)の両方のレベルでトーンを分析できます。
Tone Analyzer

Tone Analyzerを使う準備

IBMクラウドのログインページよりIBMクラウドにログインします。

https://cloud.ibm.com/login
※ アカウントの無い方は新規アカウントを作成して下さい。アカウントは無料で作成できます。

IBM Watsonのサービス選択ページよりTone Analyzerを選択します。

https://cloud.ibm.com/developer/watson/services
Tone Analyzer

Tone Analyzerのライト・プランを選択し作成ボタンを押します。

Tone Analyzer ※ ライト・プランはAPIを1ヶ月2,500件まで無料で利用できます。
※ 上記ハードコピーはライト・プラン登録後に取得したため警告が出ていますが、初回は警告は出ません。

Tone Analyzerのライト・プランサービスのAPIキーとAPI URLを確認します

Tone AnalyzerAPIキーとAPI URLはAPIを使うのに必要なのでメモして下さい。
APIキーはあなたのAPI利用プランを使うための認証情報なので他人には公開しないでください。

Tone AnalyzerをPythonで使う準備

# pipコマンドでIBM WatsonのPythonライブラリをインストールする
pip install ibm_watson

Tone Analyzerの使い方(Pythonの実装例)

from ibm_watson import ToneAnalyzerV3
import json

# Tone Analyzerのインスタンス生成
tone_analyzer = ToneAnalyzerV3(
  version = '2019-09-01',     # APIバージョン(2019-09-01時点で最新のVERを設定)
  iam_apikey = APIKEY_TA,     # APIキー
  url = APIURL_TA     # API URL
)

# Tone Analyzerの実行
tone_analysis = tone_analyzer.tone(
  {'text': '分析対象のテキストXXXXXXXXXXXXXXXXXXXXXXXXXX'},
  content_type='application/json'
).get_result()

# 実行結果の表示
print(json.dumps(tone_analysis, indent=2))

Tone Analyzerの実行結果サンプル

# 解析テキスト
I used it for my last shopping and shower as my home flight was late at night. The hotel is not available for about six hours, but it was very comfortable in Pratnam's shopping, consolidation, and shower because it was close to the "Ratchaparok" station on the Airport Link.  However, the 502 air-conditioner was bad, and 504 wasn't refrigerated. Well, it was a sum of money, and I did not stay in the room, so I laughed.

# 実行結果
{
  "document_tone": {
    "tones": [
      {
        "score": 0.564087,
        "tone_id": "analytical",
        "tone_name": "Analytical"
      }
    ]
  },
  "sentences_tone": [
    {
      "sentence_id": 0,
      "text": "I used it for my last shopping and shower as my home flight was late at night.",
      "tones": []
    },
    {
      "sentence_id": 1,
      "text": "The hotel is not available for about six hours, but it was very comfortable in Pratnam's shopping, consolidation, and shower because it was close to the \"Ratchaparok\" station on the Airport Link.",
      "tones": [
        {
          "score": 0.528951,
          "tone_id": "joy",
          "tone_name": "Joy"
        },
        {
          "score": 0.506763,
          "tone_id": "analytical",
          "tone_name": "Analytical"
        }
      ]
    },
    {
      "sentence_id": 2,
      "text": "However, the 502 air-conditioner was bad, and 504 wasn't refrigerated.",
      "tones": [
        {
          "score": 0.687768,
          "tone_id": "analytical",
          "tone_name": "Analytical"
        }
      ]
    },
    {
      "sentence_id": 3,
      "text": "Well, it was a sum of money, and I did not stay in the room, so I laughed.",
      "tones": [
        {
          "score": 0.697738,
          "tone_id": "joy",
          "tone_name": "Joy"
        }
      ]
    }
  ]
}

実行結果の説明

document_tone オブジェクト

文章全体のトーン(感情)の解析結果。一つのtonesオブジェクトを持つ。
tonesオブジェクトのtone_idが文章全体のトーンの解析結果で以下の何れかのトーン(感情)が設定される。

  • anger:怒り
  • fear:恐れ
  • joy:喜び
  • sadness: 悲しみ
  • analytical:分析的
  • confident:自信
  • tentative:暫定

sentences_toneオブジェクト

文節ごとのトーン(感情)の解析結果。文節のリスト配列で構成され各要素がtonesオブジェクトを持つ。 tonesオブジェクトの要素はdocument_tone と同様。

Tone Analyzerリファレンス

cloud.ibm.com

3.Tone Analyzerは日本語対応していない

Tone Analyzerは日本語対応していない

2019年9月現在はTone Analyzerは残念ながら日本語に対応していません。Tone Analyzerの類似のサービスでテキストから性格分析を行うPersonality Insightsは日本語に対応しているので、しばらくすればTone Analyzerも日本語対応されると思いますが、現時点でTone Analyzerは日本語に非対応です。

Tone Analyzerで日本語のテキストを解析する方法

Tone Analyzerが日本語に対応していない以上、日本語をTone Analyzerで解析可能な言語(英語)に変換してからTone Analyzerを使う必要があります。 幸いなことに翻訳も今の時代はAIで簡単に出来ます。Google CloudでもIBM Watsonを使って日本語を英語に翻訳しましょう。個人的な感覚では翻訳はGoogle に軍配が上がる気がしますが、今回はIBM Watsonでコードを統一したかったので、IBM WatsonのLanguage Translatorを使って翻訳をしました。

IBM WatsonのLanguage Translatorの使い方

from ibm_watson import LanguageTranslatorV3
import json

# Language Translatorのインスタンス生成
language_translator = LanguageTranslatorV3(
  version = '2019-09-01',     # APIバージョン(2019-09-01時点で最新のVERを設定)
  iam_apikey = APIKEY_LT,   # APIキー
  url = APIURL_LT    # API URL
)

# 翻訳の実行
translation = language_translator.translate(
  text = '翻訳対象のテキストXXXXXXXXXXXXXXXXXXXXXXXXXX',
  source = 'ja',    # 翻訳元言語(日本語)
  target = 'en'    # 翻訳先言語(英語)
)
text_en = translation.result['translations'][0]['translation']

# 実行結果の表示
print(text_en)

Language Translatorリファレンス

cloud.ibm.com

気になるTone Analyzerの精度は?

AIで翻訳したテキストをTone Analyzerは正しく解析できるのか気になりましたが、結構正確に分析してくれました。

# 例1
# 原文(日本語)
4階の角部屋でしたが、窓が閉まらないしすぐ横に駐車場?があったせいで、部屋の中がずっと変な匂いしてました。 階ごとにwifiが飛んでますが、場所が悪 いせいか部屋の中では全く使えませんでした ですが、この値段ですし、部屋にトイレもシャワーも冷蔵庫もクーラーもあるので、文句はあまり言いません

# Language Translator翻訳(英語)
It was a corner room on the fourth floor, but the window was closed or a parking garage right next to it?I had a strange smell in my room because of the time being. I couldn't use wifi on every floor, but I couldn't use it at all in the room or in the room. But I'm not going to complain about it because there's a room in the room, a shower, a refrigerator and a cooler.

# Tone Analyzerの解析結果の抜粋
    {
      "sentence_id": 1,
      "text": "I couldn't use wifi on every floor, but I couldn't use it at all in the room or in the room.",
      "tones": [
        {
          "score": 0.548768,
          "tone_id": "anger",
          "tone_name": "Anger"
        },
     → angerと判断している。

# 例2
# 原文(日本語)
帰国便が深夜発だったので、最後の買い物とシャワーの為に利用しました。 利用時間約6時間で宿泊はしていませんが、Airport Link のRatchaparok 駅の近 くなので、プラトゥナムでの買い物→整理、シャワーには快適でした。  ただ、502は、エアコンの効きが悪く、504は、冷蔵庫がなかったです。 まぁそこは金額が金額だし、宿泊しないので笑って済ませました。

# Language Translator翻訳(英語)
I used it for my last shopping and shower as my home flight was late at night. The hotel is not available for about six hours, but it was very comfortable in Pratnam's shopping, consolidation, and shower because it was close to the "Ratchaparok" station on the Airport Link.  However, the 502 air-conditioner was bad, and 504 wasn't refrigerated. Well, it was a sum of money, and I did not stay in the room, so I laughed.

# Tone Analyzerの解析結果の抜粋
      "text": "The hotel is not available for about six hours, but it was very comfortable in Pratnam's shopping, consolidation, and shower because it was close to the \"Ratchaparok\" station on the Airport Link.",
      "tones": [
        {
          "score": 0.528951,
          "tone_id": "joy",
          "tone_name": "Joy"
        },
     → joyと判断している。

4.【実装例】AIでタイの5つ星ホテルをランキングしてみた

AIでタイの5つ星ホテルをランキングしてみた

私はもう一つのブログで旅行の記事を書いていて、ホテルの紹介記事でも書いてみようかなと思ったので、Language TranslatorとTone Analyzerを使ってタイの5つ星ホテルのランキングをしてみました。
travel5.hateblo.jp

実装ソース

# coding: UTF-8
import urllib3
from bs4 import BeautifulSoup
import certifi
import json
from ibm_watson import LanguageTranslatorV3
from ibm_watson import ToneAnalyzerV3
import sys

# 分析対象の口コミサイト(★)
TARGET_DOMAIN = "https://www.tripadvisor.jp"
TARGET_TOPPAGE = "/Hotel_Review-g293916-d1647893-Reviews-Siam_Star_Hotel-Bangkok.html"  

APIKEY_LT = "xxxxxここには自分のLanguage TranslatorのAPIキーを入れるxxxxxx"
APIURL_LT = "https://gateway-tok.watsonplatform.net/language-translator/api"
APIKEY_TA = "xxxxxここには自分のTone AnalyzerのAPIキーを入れるxxxxxx"
APIURL_TA = "https://gateway-tok.watsonplatform.net/tone-analyzer/api"
API_VERSION = '2019-09-01'

result_map = {
  "url" : "",
  "joy" : 0,
  "anger" : 0,
  "sadness" : 0,
  "fear" : 0,
  "total" : 0
}

# 口コミ検索処理
def getEvalData(url):
  if result_map['total'] > 100:
    return

  print(url)
  # httpsの証明書検証を実行
  http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where())

  # ページデータ取得
  html = http.request('GET', url)
  soap = BeautifulSoup(html.data, 'html.parser')

  # 口コミ取得
  for qs in soap.find_all('q'):
    try:
      for span in qs.find_all('span'):
        text = span.text
        print('===================')
        print(text)
        print('---')
        text_en = langTranslate(text)
        toneAnalyze(text_en)
        break
    except:
      print('Error')

  # ボタンリンク取得
  a = soap.find('a', class_='next')
  if a is not None:
    url = TARGET_DOMAIN + a.attrs['href']
    result_map['url'] = url
    getEvalData(url)

# 日本語→英語翻訳
def langTranslate(text):
  language_translator = LanguageTranslatorV3(
    version = API_VERSION,
    iam_apikey = APIKEY_LT,
    url = APIURL_LT
  )
  translation = language_translator.translate(
    text = text,
    source = 'ja',
    target = 'en')
  text_en = translation.result['translations'][0]['translation']
  print(text_en)
  return text_en

# 口コミ分析
def toneAnalyze(text):
  tone_analyzer = ToneAnalyzerV3(
    version = API_VERSION,
    iam_apikey = APIKEY_TA,
    url = APIURL_TA
  )

  tone_analysis = tone_analyzer.tone(
    {'text': text},
    content_type='application/json'
  ).get_result()
#  print(json.dumps(tone_analysis, indent=2))
  calcScore(tone_analysis)

# スコア判定
def calcScore(resultMap):
  # document_tone
  if ('document_tone' in resultMap):
    for tones in resultMap['document_tone']['tones']:
      tone_id = tones['tone_id']
      if (tone_id == 'joy' or tone_id == 'anger' or 
          tone_id == 'sadness' or tone_id == 'fear'):
        result_map[tone_id] = result_map[tone_id] + 1
        result_map['total'] = result_map['total'] + 1
        print('---')
        print(tone_id)

  # sentences_tone
  if ('sentences_tone' in resultMap):
    for sentences in resultMap['sentences_tone']:
      print('---')
      print(sentences['text'])
      for tones in sentences['tones']:
        tone_id = tones['tone_id']
        if (tone_id == 'joy' or tone_id == 'anger' or 
            tone_id == 'sadness' or tone_id == 'fear'):
          result_map[tone_id] = result_map[tone_id] + 1
          result_map['total'] = result_map['total'] + 1
          print(tone_id)

if __name__ == '__main__':
  args = sys.argv
  url = TARGET_TOPPAGE
  if (len(args) >= 2):
    url = args[1]
  getEvalData(TARGET_DOMAIN + url)
  print('### reulst ###')
  print(result_map)

実行結果

注) 上記のサンプルソースは1ホテルの分析にしか対応していません。以下の一覧は上記ソースの★印の箇所を都度置き換えて作成しましたものです。

ホテル名AIの評価口コミサイトの評価備考
The Raweekanlaya Bangkok974.5
アカラ ホテル955
エバーグリーン ローレル ホテル934.5
アル メロス ホテル904.5
シャーマレイクビューアソーク904
ザ バークレイ ホテル プラトゥーナム904
センタラ グランド アット セントラル プラザ ラープラオ バンコク894.5
アーバナ サトーン883.5
ドリーム バンコク884.5
アエタス ルンピニ884.5
モンティエン リバーサイド ホテル874
ザ グランド フォーウィングス コンベンション ホテル874
グランド メルキュール アソーク レジデンス864.5
ラマダ プラザ メナム リバーサイド854
プリンス パレス ホテル843.5
ザ イータス バンコク834.5
アマリ アトリウム ホテル834
ジャスミン リゾート ホテル814
ザ イータス レジデンス804.5
The Bazaar Hotel-3口コミ100件以下
Prince Suites Residence Managed By Prince Palace-3.5口コミ100件以下
The Park Nine Suvarnabhumi-4.5評価材料となる口コミが100件以下

試した感想

トップ1と2は確かに良いなーと思いました。たぶん口コミをきちんと評価しています。
5つ星ホテルだからどれも良いんですが・・・。

今回はjoyをポジティブ、 anger、sadness、fearをネガティブと判断したのですが、joy、 anger、fearは正しく判断している様に感じましたが、sadnessが何か違う気もします。
「疲れた時にシャワーが使えて良かった」という文をsadnessと評価していました。恐らく「疲れた」をネガティブな表現と判断したのだと思います。まだ改良は必要かもしれません。何の感情も無い文章はTone Analyzerがjoy、anger、sadness、fearの何れも返さないので評価対象とならないことは良かったです。

口コミ評価 それではまたー💛