センチメント分析モデルで遊んでみた


AIって結局何なのかよく分からないので、とりあえず100日間勉強してみた Day42


経緯についてはこちらをご参照ください。



■本日の進捗

●センチメント分析を理解

■はじめに

引き続き「Pythonではじめる機械学習(オライリー・ジャパン)」で学んでいきます。

前回に引き続きBoWを用いたセンチメント分析を行っていき、その挙動を深堀していきます。

■センチメント分析モデル

前回は交差検証を用いてセンチメント分析のスコアを確認し、BoWを噛ませるだけでそれなりの精度が出ることを確認しました。

https://hammer-time.org/699

まずは交差検証にてロジスティック回帰のC値に目星を付けておきます。(より良いモデルで性能を見ていきたいが、毎回25000のドキュメントで交差検証をかけるのは計算コストがかかるため)

import numpy as np
from sklearn.datasets import load_files
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV

reviews_train = load_files("C:/Users/****/Documents/Python/aclImdb/train")
text_train, y_train = reviews_train.data, reviews_train.target

reviews_test = load_files("C:/Users/****/Documents/Python/aclImdb/test")
text_test, y_test = reviews_test.data, reviews_test.target

vectorizer = CountVectorizer()
X_train = vectorizer.fit_transform(text_train)
X_test = vectorizer.transform(text_test)

param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 100]}

grid = GridSearchCV(LogisticRegression(max_iter=10000), param_grid, cv=5, n_jobs=-1)
grid.fit(X_train, y_train)

print("cv best score: {:.2f}".format(grid.best_score_))
print("best parameter: {}".format(grid.best_params_))

前回のデフォルト設定より少しだけ交差検証内側のスコアは高かったみたいです。C=0.1が最も良さそうなので、この値を用いていきます。(もちろんこのグリッドパラメータの範囲での最適解なだけでありCを最適化できている保証はないですが、ここではそこまでの性能を求めません。)

次にテストデータからいくつかのレビューコメントとラベルを見てみます。

import numpy as np
from sklearn.datasets import load_files
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression

reviews_train = load_files("C:/Users/****/Documents/Python/aclImdb/train")
text_train, y_train = reviews_train.data, reviews_train.target

reviews_test = load_files("C:/Users/****/Documents/Python/aclImdb/test")
text_test, y_test = reviews_test.data, reviews_test.target

indices = [8, 16, 57, 65]

for i in indices:
    print(f"test data[{i}] :{text_test[i]}")
    print(f"test label[{i}] :{y_test[i]}")

テストデータ[8]

オーシャンズ12:他の2本とは比べ物にならないくらいくだらない、駄作。アートの横取り。10人の有名俳優が出演しているが、弱い台本とつまらないアイディアのせいで、20分しか見ていないがそう評価する。誤解しないでほしいが、もしかしたら気に入る人もいるかもしれない。だが、僕がオーシャンズ映画が好きなのは、強盗というテーマがあるからだ。もし『オーシャンズ12』が強盗がテーマでないなら、何のために見るのだろうか?
ソダーバーグ監督が自分の主な誤りに気づき、最初の作品よりはるかに優れた映画を作ることで挽回したことを嬉しく思う。それは称賛に値する。
スティーブン・ソダーバーグはあまりいい監督ではない。ヒット作「セックス・ライツ・アンド・ビデオテープ」を除けば、この監督のキャリアにこれほど素晴らしい出来事は他になかった。恥ずべきことだ。しかし、それは彼の責任に他ならない。

前回も取り上げたレビューですが、どこから見ても明らかなネガティブコメントです。

テストデータ[16]

出演のトップに名を連ねる偉大なジェームズ・キャグニーは、映画の後半3分の1まで登場せず、恐らく悪の少年院長を演じるダドリー・ディッジスよりも出演は短い。しかし、少年院を改革しようとする副長官として登場するジミーは、空気を切り裂き、つま先で飛び跳ね、ワーナー・ファースト・ナショナルのパンチの効いたセリフを、いつもの期待通りの華麗さで吐き出す。ワーナーが「社会意識の高い」スタジオとしての地位を確立しようと努力する数々の試みの1つであるこのさわやかなアンティーク作品の心理は、深いところまで達していない。ディッジスが下手なのは、脚本でそう求められているからであり、少年犯罪者もほんの少しの自主性を与えれば立派な子供に変わるという古風な考えがある。しかし、スタジオが得意とする簡素でテンポの速いスタイルで作られており、決して飽きさせない。ワーナーのお気に入りのロッテン・ストリート・キッドとして短期間出演した際、スクリーン上でさまざまなトラブルに巻き込まれたフランキー・ダロは、理想的な配役だ。短い鼻と鋼鉄さえも枯らしてしまうほどの憎しみに満ちた視線を持つ、ハンサムでカリスマ性のあるタフガイだ。現代の子役で彼にかなう者はいない。

今回表示した中で唯一のポジティブコメントですが、すべてを称賛しているわけではなく出演時間の短さや足りていない部分、批判的な単語を用いた称賛があったりと、単語だけで感情を分析するには難しそうです。

テストデータ[57]

ひどい。この番組が面白いと唯一思えるのは、この番組が自虐している時だけです。「すごい。犯罪と戦う**。しかも彼は酒もタバコもやる! なんて面白いんだ! たいていの人が口に入れるものを、彼は自分で口に入れるから面白い! そして今、彼は女性から性的サービスを受けている! この番組は最高!」これは、この番組が気に入ったならば言わなければならないことですが、明らかに皮肉が込められていることはおわかりでしょう。この番組を「12 oz. Mouse」や「Squid Billies」と比較している人がいます。なぜ比較するのでしょうか? 比較するものは何もありません。他の 2 つの番組は、実際にキャラクターがきちんとしています。結論として、私は Assy Mcgee が嫌いです。名前を聞くだけでゾッとします。

全体に渡って痛烈な批判が続くネガティブコメントです。しかし自身で言及しているようにコメントの3割ほどを占める皮肉セクション(やはり人間にも機械学習アルゴリズムにもアイロニーを学習するのは難しい)は、単語だけを取り上げれば極端に称賛的にも見えます。

テストデータ[65]

最高に面白い映画というわけではないが、ミシェル・ジョンソンにもう一度恋するために、少なくとも年に一度はこの映画を見なければならない。この映画での彼女は、これまで見たことがないほど素晴らしかった。ちなみに、ストーリーも良い。

とてもシンプルなポジティブコメントですが、ラベルはClass 0、ネガティブコメントです。なぜ???

訓練データをロジスティック回帰(もちろんC=0.1)で学習させたモデルを構築して、上記のテストデータに対するセンチメント分析の結果を見てみましょう。わくわくしますね!!!

import numpy as np
from sklearn.datasets import load_files
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression

reviews_train = load_files("C:/Users/****/Documents/Python/aclImdb/train")
text_train, y_train = reviews_train.data, reviews_train.target

reviews_test = load_files("C:/Users/****/Documents/Python/aclImdb/test")
text_test, y_test = reviews_test.data, reviews_test.target

vectorizer = CountVectorizer()
X_train = vectorizer.fit_transform(text_train)
X_test = vectorizer.transform(text_test)

model = LogisticRegression(C=0.1, max_iter=10000, n_jobs=-1)
model.fit(X_train, y_train)

y_pred = model.predict(X_test)

indices = [8, 16, 57, 65]
for i in indices:
    print(f"TestData[{i}]: Actual Class: {y_test[i]}, Predicted Class: {y_pred[i]}")

結果を見る前に、このモデルがAccuracyでおよそ0.89の十分な精度を持つことを忘れないでください。今回表示していない大量のコメントの8割以上を正確に分類できています。

さて、センチメント分析の結果を見てみると、明らかなネガティブコメントだったテストデータ[8]は正確にネガティブに分類できているようですが、それ以外は予測を外しています。

テストデータ[16]のようなポジティブではあるものの冷静な評価をしているコメントに対しては個々の単語に分割しての評価は難しいのかもしれません。そして全体的な文字数が多くこれは予測モデルに対してはノイズになるでしょう。

テストデータ[57]はやはりといった結果で、皮肉セクションで大量に表れる称賛的な単語を見ればポジティブコメントに分類してしまう気持ちもよくわかります。これはテストデータとして結構難しい方だと思われるので手法を改善するしかないでしょうか。

テストデータ[65]については、予測モデルはポジティブコメントに分類していますが、ラベルはネガティブコメントになっているため予測を外しているようです。親心?ではないですが、自分は予測モデルの方を支持したいです。なぜこれがネガティブコメントにラベリングされているのか分かる方がいたら是非教えてください。英語圏的にはこれも皮肉なのでしょうか???

■おわりに

BoWを用いることで機械学習アルゴリズムに学習させることができ、テキストデータに対しても十分な学習ができることが分かりました。そして皮肉や中立性、文字数の多さに対するセンチメント分析の結果から、BoWにおける全単語の分離による欠点も見えてきました。でもやはりテキストデータはその意味が分かりやすいという点でデータの解釈が簡単なので面白いですね。

それにしてもいつの間にかDeepLよりGoogle Translateの方が精度が良くなってるんですけど知ってました?どのツールも進歩が早いですね。

■参考文献

  1. Andreas C. Muller, Sarah Guido. Pythonではじめる機械学習. 中田 秀基 訳. オライリー・ジャパン. 2017. 392p.
  2. ChatGPT. 4o mini. OpenAI. 2024. https://chatgpt.com/
  3. API Reference. scikit-learn.org. https://scikit-learn.org/stable/api/index.html
  4. Maas, Andrew L. and Daly, Raymond E. and Pham, Peter T. and Huang, Dan and Ng, Andrew Y. and Potts, Christopher, Learning Word Vectors for Sentiment Analysis, Proceedings of the 49th Annual Meeting of the Association for Computational Linguistics: Human Language Technologies, June, 2011, Portland, Oregon, USA, Association for Computational Linguistics, 142–150, http://www.aclweb.org/anthology/P11-1015
  5. Potts, Christopher. 2011. On the negativity of negation. In Nan Li and David Lutz, eds., Proceedings of Semantics and Linguistic Theory 20, 636-659.


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です