Amazonレビューは、何かと話題になります。
今なら、Amazonレビューにはサクラが多くて胡散臭いという話題でしょうか?
Amazonレビューは、以前は本当に役に立ちました。
参考にして買い物をすることも多くありました。
しかし、今はレビューを参考にすることが、めっきりと減りました。
そもそも、Amazonでの買い物をする機会が減りました。
その代わりに、安全なイメージのヨドバシで買い物をしています。
レビュー以外にも、悪質な業者の問題がAmazonには存在していますからね。
そのイメージの悪いAmazonレビューに関して、この記事で取り上げます。
どう取り上げるかと言うと、センチメント分析(感情分析)の対象とします。
本記事の内容
- Amazonレビューをセンチメント分析(感情分析)する目的・意図
- Amazonレビューを取得(データ収集)する
- Amazonレビューをセンチメント分析(感情分析)する
- Amazonレビューのセンチメント分析結果
- センチメント分析(感情分析)は使えない!?
それでは、上記に沿って解説していきます。
Amazonレビューをセンチメント分析(感情分析)する目的・意図
Amazonレビューには、多くの情報が集まっています。
まず、その投稿の量が圧倒的です。
確かに、サクラも多いのでしょう。
でも、サクラ以外の真っ当なレビューも多く投稿されています。
その投稿数が、他サイトとは比較にはなりません。
ヨドバシでは、レビューはほとんど投稿されないようです。
その意味でも、Amazonのレビューには価値があります。
また、コメントと評価(星1~5)がセットになっているのもポイントです。
このようにセットになっている点が、データ分析の際には役に立ちます。
以上より、Amazonレビューにはデータ量と内容(コメントと評価)が備わっていると言えます。
そして、何よりもネガポジ分析を実際のデータでやりたかったというのが大きいです。
自分にも身近なデータで分析する方が、モチベーションも沸きますからね。
Amazonレビューを取得(データ収集)する
データ分析の最初の関門となります。
どうやってデータを大量に集めるのか?ということですね。
これに関しては、全く問題ありません。
本ブログでは、多くのサイトをスクレイピングした結果を記事にしています。
その中でも、次の記事は今回の作業にビンゴです。
上の記事の内容を若干修正して、データを集めました。
改良したコードは以下。
import bs4
import time
import re
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import pandas as pd
CHROME_DRIVER = "chromedriver.exeのパス"
FILE_PATH = "./amazon_data/review.json"
# Amazonページ取得
def get_page_from_amazon(url):
text = ""
# ヘッドレスモードでブラウザを起動
options = Options()
options.add_argument('--headless')
# ブラウザーを起動
driver = webdriver.Chrome(CHROME_DRIVER, options=options)
driver.get(url)
driver.implicitly_wait(10) # 見つからないときは、10秒まで待つ
text = driver.page_source
# ブラウザ停止
driver.quit()
return text
# 全ページ分をリストにする
def get_all_reviews(url):
rvw_list = []
i = 1
while True:
print(i,'searching')
i += 1
text = get_page_from_amazon(url)
amazon_soup = bs4.BeautifulSoup(text, features='lxml')
for ratings in amazon_soup.find_all("div", attrs={"data-hook": "review"}):
submission_date = ratings.find("span", {'data-hook':'review-date'}).text
rating = ratings.find('i', attrs={"data-hook": "review-star-rating"}).text
review_txt = ratings.find("span", {'data-hook':'review-body'}).text
#paid = ratings.find("span", attrs={"class": "a-color-success a-text-bold"})
print(submission_date + "@" + rating + "@" + review_txt)
print('\n')
if submission_date:
rating = rating.replace("5つ星のうち", "")
submission_date = extract_date(submission_date)
info = {}
info["postdate"] = submission_date
info["rating"] = rating
info["review_txt"] = review_txt
rvw_list.append(info)
# 次へボタン
next_page = amazon_soup.select('li.a-last a')
if next_page != []:
next_url = 'https://www.amazon.co.jp/' + next_page[0].attrs['href']
url = next_url
# 最低でも1秒は間隔をあける
time.sleep(1)
else:
break
return rvw_list
def extract_date(s):
date_pattern = re.compile('(\d{4})年(\d{1,2})月(\d{1,2})日')
result = date_pattern.search(s)
if result:
y, m, d = result.groups()
return str(y) + str(m.zfill(2)) + str(d.zfill(2))
else:
return None
if __name__ == '__main__':
# Amzon商品ページ
url = 'https://www.amazon.co.jp/dp/B081CR9LQ1?pf_rd_r=9G7DP9DBQV9R5WWBA7GB&pf_rd_p=cf3dd3d4-7c29-4fa2-a9b7-8e9f95c1f37f&pd_rd_r=56934866-4323-49ea-ae8e-289260468100&pd_rd_w=bIWmn&pd_rd_wg=gA4B0&ref_=pd_gw_ci_mcx_mr_hp_d'
# URLをレビューページのものに書き換える
new_url = url.replace('dp', 'product-reviews')
# レビューの取得
rvw_list = get_all_reviews(new_url)
# データフレームに変換
df = pd.DataFrame(rvw_list)
# jsonとして保存
df.to_json(FILE_PATH, orient='records')
内容に不明な点があれば、過去記事を参考にしてください。
詳細を説明しています。
このサンプルコードを動かすと、該当するAmazonの商品ページのレビューを収集します。
その結果は、amazon_dataフォルダ内のreview.jsonに保存されます。
- 投稿日
- 評価
- コメント
項目的には、上記の3つとなります。
Amazonレビューをセンチメント分析(感情分析)する
センチメント分析(感情分析)は、難しそう。。。
このように思うかもしれません。
ただ、分析するだけなら簡単にできます。
やり方は以下。
- 単語感情極性対応表(ネガポジ辞書)を取得する
- 分析対象の文章を単語に分割する(形態素解析)
- ネガポジ辞書と単語を比較する(否定・肯定の判定)
では、上記を説明していきましょう。
単語感情極性対応表(ネガポジ辞書)を取得する
以下のページにアクセスします。
「日本語」のリンク先が辞書となります。
http://www.lr.pi.titech.ac.jp/~takamura/pndic_ja.html
優れる:すぐれる:動詞:1 良い:よい:形容詞:0.999995 喜ぶ:よろこぶ:動詞:0.999979 褒める:ほめる:動詞:0.999979 めでたい:めでたい:形容詞:0.999645 ~ 厄難:やくなん:名詞:-0.765276 紡ぐ:つむぐ:動詞:-0.765358 自製:じせい:名詞:-0.765388 死亡:しぼう:名詞:-0.765674 主義:しゅぎ:名詞:-0.765714
上記がその内容です。
単語毎に値が設定されています。
その値の範囲は、-1から1までとなります。
1に近いほど、肯定的なワードです。
-1に近いほど、否定的なワードです。
分析対象の文章を単語に分割する(形態素解析)
文章を形態素解析します。
形態素解析に関しては、次の記事で詳しく説明しています。
プログラム的には、複雑なことはしません。
専用のソフトを用いて、簡単に行うことができます。
今回は、MecabをPythonから用いて形態素解析を行っています。
ネガポジ辞書と単語を比較する(否定・肯定の判定)
ここまで説明してきたら、わかると思います。
形態素解析によって、文章毎(レビューのコメント)に単語が求められます。
そして、その単語が単語感情極性対応表(ネガポジ辞書)にあるかどうかを調べます。
あった場合は、何点(-1~1の間の数値)なのかを求めます。
複数の単語がマッチする場合は、その平均を用います。
Amazonレビューのセンチメント分析結果
約9000件のレビューを分析しました。
上記のデータ収集プログラムで集めたデータです。
以下の3つの結果を確認しましょう
- ヒストグラム
- 散布図
- 結果一覧
では、それぞれを確認します。
ヒストグラム

基本的には、ネガティブの結果が多いです。
9割以上が、0以下という結果ですね。
ヒストグラムに関しては、次の記事が参考になります。
簡単にヒストグラムの図を作成できます。
レビューのコメントには、ネガティブな結果が多いことはわかりました。
では、その結果と評価(星1~5)との関係が気になります。
その二つの値の関係性を見るには、散布図が約に立ちます。
以下で、それを確認しましょう。
散布図

横(x軸)が、ネガポジ(PN)結果の値です。
縦(y軸)が、Amazonレビューにおける評価です。
この結果を見ると、次のことが言えます。
- 低評価(1と2)にはネガティブなコメントしかない
- 高評価にもネガティブなコメントが多い
- 基本的にはネガティブなコメントが多い
結果一覧
結果を直接確認します。
まずは、ポジティブなコメントから。
つまり、値が1に近いモノということです。

pn:ネガポジ分析の値
rating:Amazonレビューにおける評価(星)
review_text:Amazonレビューにおけるコメント
確かに、肯定的なコメントが並びます。
あと、コメントが短いというのが目立ちますね。
次は、ネガティブなコメントを確認しましょう。
pnが-1に近いモノということです。

どうもオカシイ。。。
まあ、これが単語感情極性対応表(ネガポジ辞書)を単純に利用した場合の限界ですね。
「言うことなし」の「なし」が、ネガティブ判定されているのです。
「部屋の汚れが少なくなって来ました」では、「汚れ」や「少なく」がネガティブとされているのでしょう。
文脈に沿った分析を行えていないという証拠になります。
単純に、単語で判定するとこのような結果になってしまうのでしょう。
センチメント分析(感情分析)は使えない!?
センチメント分析(感情分析)を行ってきました。
正直、微妙ですね。
散布図を見る限りでは、全く見当違いというわけでもないようです。
そのため、「センチメント分析(感情分析)は使えない」と断定するのは時期早々でしょう。
これは、あくまでセンチメント分析(感情分析)のスタートです。
ここからネガポジ判定の精度をどうやって上げていくのか?
単語感情極性対応表(ネガポジ辞書)にもっと情報を増やすのか?
それとも、文脈を考慮した分析方法があるのか?
センチメント分析(感情分析)における課題ですね。
それでは、最後にセンチメント分析(感情分析)を行ったサンプルコードを載せておきます。
import pandas as pd
import json
import MeCab
import re
import matplotlib.pyplot as plt
import numpy as np
FILE_PATH = "./amazon_data/review.json"
DIC_PATH = "-d ipadic-neologdのパス" # 辞書ipadic-neologdがあれば、そのパスを記述
def get_dic_list(text):
mecab = MeCab.Tagger(DIC_PATH)
parsed = mecab.parse(text)
lines = parsed.split('\n')
lines = lines[0:-2]
dic_list = []
for line in lines:
tmp = re.split('\t|,', line)
dic = {'dsp':tmp[0], 'kind_1':tmp[1], 'kind_2':tmp[2], 'value':tmp[7]}
dic_list.append(dic)
return dic_list
# PN判定
def judge_pn(pn_dict, dic_list):
all_pn = 0
count = 0
result = ""
for word in dic_list:
base = word['value']
if base in pn_dict:
count = count + 1
pn = float(pn_dict[base])
all_pn = all_pn + pn
if all_pn != 0:
result = all_pn / count
return result
# Amazonレビューの読み込み
json_open = open(FILE_PATH, 'r')
review_list = json.load(json_open)
# ネガポジ辞書の読み込み
pn_df = pd.read_csv('dic/pn_ja.dic.txt',\
sep=':',
encoding='utf-8',
names=('Word','Reading','POS', 'PN')
)
# ネガポジ辞書をデータフレームからdict型に変換
word_list = list(pn_df['Word'])
pn_list = list(pn_df['PN'])
pn_dict = dict(zip(word_list, pn_list))
new_review_list = []
for review in review_list:
review_txt = review["review_txt"]
rating = review["rating"]
postdate = review["postdate"]
dic_list = get_dic_list(review_txt)
pn = judge_pn(pn_dict, dic_list)
review["pn"] = pn
if pn:
new_review_list.append(review)
new_review_list_df = pd.DataFrame(new_review_list)
# 欠損値が一つでも含まれる行を削除
new_review_list_df = new_review_list_df.dropna(how='any')
x = new_review_list_df["pn"].astype(float)
y = new_review_list_df["rating"].astype(float)
fig = plt.figure(dpi=100, figsize=(4.6,3.8))
#fig.suptitle('評価:PN', fontsize=10, x=0.27, y=0.87)
ax = fig.add_subplot(111)
ax.yaxis.set_label_coords(-0.07,0.4)
# 目盛の値
xscale = np.arange(-1.0, 1.1, 0.2)
yscale = np.arange(0, 6, 1.0)
# 散布図を描画
plt.scatter(x, y, c='#00FFFF', edgecolors="#37BAF2")
plt.title("評価・PN散布図", fontsize=17)
plt.xticks(xscale, fontsize=8)
plt.yticks(yscale, fontsize=8)
plt.xlabel("PN", fontsize=10)
plt.ylabel("評\n価", fontsize=10, rotation=0)
plt.xlim(-1.1, 1.1)
plt.ylim(0.5, 5.5)
plt.subplots_adjust(left=0.1, right=0.98, bottom=0.13, top=0.89)
plt.savefig("result_1.png", facecolor="white")
"""
# グラフを表示
plt.hist(x)
# グラフを画像保存
plt.savefig("result_2.png", facecolor="white")
"""










