先日株式会社チームゼットさん主催のPython勉強会に参加してきました。今回のテーマは「word2vecを用いたテキストの感情
分析」とのこと。
正直1週間前にPythonを初めて触った僕にはチンプンカンプンなテーマだったのでが、今勉強している文法がどのように生かされて形になっているのかを体感しにいくのもありかな、と思い開催一日前に、慌てて駆け込み乗車しました。
さて、前置きはこのくらいにしておいて本題に入っていきます。
#そもそもWord2Vecって???
単語を分析するニューラルネットワークモデル(機械学習)。簡単に言うと単語をベクトル化して、重みづけできるというものらしいです。(より詳しく知りたい方はこちらを参考に)
今回は
白ヤギコーポレーションさん
のword2vecモデルをもちいました。
word2vecの導入方法はこちら
まずは、
word2vecによって単語がベクトル化されていることを確認しましょう。
word2vecが実装されている状態でこちらのコードを打ってみましょう。
import gensim.models.word2vec.Word2Vec as wv
print(len(model.wv["愛"]))
model.wv["愛"]
すると
50
array([ 0.09289702, -0.16302316, -0.08176763, -0.29827002, 0.05170078,
0.07736144, -0.06452437, 0.19822665, -0.11941547, -0.11159643,
0.03224859, 0.03042056, -0.09065174, -0.1677992 , -0.19054233,
0.10354111, 0.02630192, -0.06666993, -0.06296805, 0.00500843,
0.26934028, 0.05273635, 0.0192258 , 0.2924312 , -0.23919497,
0.02317964, -0.21278766, -0.01392282, 0.24962738, 0.11264788,
0.05772769, 0.20941015, -0.01239212, -0.1256235 , -0.19794041,
0.1267719 , -0.12306885, 0.01006295, 0.08548331, -0.08936502,
-0.05429656, -0.09757583, 0.10338967, 0.13714872, 0.23966707,
0.02216845, 0.02270923, 0.32569838, -0.0311841 , -0.00150117],
dtype=float32)
という結果が返ってきます。これは「愛」という単語が50次元でできており。その成分が上記の要素で構成されていることを表しています。
次に
#keywordに似ている言葉を抽出
sim_do = model.wv.most_similar(positive=["彼女"], topn=30)
# リスト化されているので、見やすいように整形
print(*[" ".join([v, str("{:.5f}".format(s))]) for v, s in sim_do], sep="\n")
と打つと
彼女自身 0.82959
モリー 0.82547
彼 0.82406
シルヴィア 0.80452
チャーリー 0.80336
恋人 0.80197
などの似たような意味の単語を抽出できます。単語の右側の数値は「彼女」という単語とどれくらいにているかを数値化したものです。
また、二つの単語がどのくらいにているかをしりたいときには
similarity = model.wv.similarity(w1="りんご", w2="イチゴ")
print(similarity)
similarity = model.wv.similarity(w1="りんご", w2="青森")
print(similarity)
similarity = model.wv.similarity(w1="りんご", w2="アンパンマン")
print(similarity)
すると
0.79041845
0.30861858
0.45321244
という値が返ってきます。w1とw2の単語がどれだけ似ているかを数値化したわけです。りんごと言ったら青森!と連想する方が多いと思うのですが、青森よりアンパンマンのほうが似ていると判断してしまっているのでこのモデルがまだ完璧なものではないことがわかりますね。
さて、ここで
「王様」ー「男」+「女」=「女王」???
という有名な命題を考えていきます。
sim_do = model.wv.most_similar(positive = ["王様", "女性"], negative=["男性"], topn=5)
print(*[" ".join([v, str("{:.5f}".format(s))]) for v, s in sim_do], sep="\n")
#positiveに入っている単語は似ている度を、negativeに入っている単語は似てない度を比較する
結果は…
お姫様 0.85313
花嫁 0.83918
野獣 0.83155
魔女 0.82982
乙女 0.82356
「女王」とぴったり一致しないものの大体似たような答えがえられました。
さて、いままで単語のみの比較をしてきましたが、ある文章がどのような感情を含んでいるのかも数値化することもできます。
import numpy as np
t = Tokenizer()
s = '
#自分の好きな文章を入れてださい。
'
output_data=[]
x = np.empty((0,4), float)
for token in t.tokenize(s):
if token.part_of_speech.split(',')[0]=="名詞" or token.part_of_speech.split(',')[0]=="形容詞":
print(token.surface)
similarity1 = model.wv.similarity(w1=token.surface, w2="嬉しい")
#print("喜び:{0}".format(similarity1))
similarity2 = model.wv.similarity(w1=token.surface, w2="楽しい")
#print("悲しみ:{0}".format(similarity2))
similarity3 = model.wv.similarity(w1=token.surface, w2="悲しい")
#print("不安:{0}".format(similarity3))
similarity4 = model.wv.similarity(w1=token.surface, w2="興奮")
#print("興味:{0}".format(similarity4))
x = np.append(x, np.array([[similarity1, similarity2, similarity3, similarity4]]), axis=0)
print("-"*30)
print(np.mean(x, axis=0))
print("嬉:{0}".format(np.mean(x, axis=0)[0]))
print("楽:{0}".format(np.mean(x, axis=0)[1]))
print("悲:{0}".format(np.mean(x, axis=0)[2]))
print("興:{0}".format(np.mean(x, axis=0)[3]))
変数sには自分の好きな文章をいれて下さい
例として
「夜景の見えるレストランでプロポーズをした」
というロマンチックな文章を入れてみましょう
結果は
夜景
レストラン
プロポーズ
[0.29473324 0.44027831 0.27123818 0.20060815]
嬉:0.29473323623339337
楽:0.4402783115704854
悲:0.27123818174004555
興:0.20060815351704755
と出てきます。つまりこのシステムは
「夜景の見えるレストランでプロポーズをした」
という文章は「楽しい」文章だと判断したことになります。(数値が大きい方がその感情が強い)
ではもう一つ例を
「深夜の刑務所で拳銃による殺人事件が起きた」
といういかにも負のオーラぷんぷんの文章を入れてみましょう
すると
深夜
刑務所
拳銃
殺人
事件
[-0.00661952 0.01671012 0.12141706 0.23172273]
嬉しい:-0.006619524117559195
楽しい:0.01671011543367058
悲しい:0.12141705807298422
興奮:0.2317227303981781
という結果に、、
実は値はマイナス値を取ることもあります。確かに嬉しさなんて一ミリも感じないですもんね。
#感想
こんな簡単に文章の感情分析ができるなんてすばらしい時代ですね。
このような有益な学びの場を与えてくださったチームゼットさんには心から感謝です