Python で日本語文章の感情分析を簡単に試す (with google colab)¶
感情分析をお手軽に試したいときに使えるツールをまとめました。
日本語文章の感情分析の手法については本記事では詳しく触れませんが、以下の記事にわかりやすくまとまっていると思います。
感情分析を簡単に試すときに使えるツール一覧¶
試してみたツールを箇条書きにして以下に示します。
-
sklearnのTfidfVectorizerとLinearSVCしか使っていない
BERT による予測と遜色ない性能
トレーニングデータセットが不明
MIT ライセンス
-
日本語評価極性辞書を利用したPython用Sentiment Analysisライブラリ oseti を公開しました - Qiita
辞書ベース
実装はシンプル
MIT ライセンス
-
a Python version of ML-Ask (eMotive eLement and Expression Analysis system)
2,100語の辞書によるパターンマッチングで{喜, 怒, 哀, 怖, 恥, 好, 厭, 昂, 安, 驚}の10種類の感情を推定
The BSD 3-Clause License
huggingface の bert-base-japanese-sentiment
ネガポジ判定 (ポジティヴとネガティヴの binary classification)
bert-base-japanese-char-whole-word-masking というモデルを自作データセットでファインチューニング
必要なライブラリのインストール¶
%%capture capt
# MeCabのインストール
!apt install mecab libmecab-dev mecab-ipadic-utf8
!pip install mecab-python3
# mecab-ipadic-NEologdのインストール
!apt install git make curl xz-utils file
!git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
!echo yes | mecab-ipadic-neologd/bin/install-mecab-ipadic-neologd -n -a
# Ref: https://qiita.com/Fulltea/items/90f6ebe6dcceaf64eaef
# Ref: https://qiita.com/SUZUKI_Masaya/items/685000d569452585210c
!ln -s /etc/mecabrc /usr/local/etc/mecabrc
# Ref: https://qiita.com/Naritoshi/items/8f55d7d5cce9ce414395
# 感情分析のためのライブラリ
!pip install -q asari oseti pymlask
# asari==0.0.4 requires Janome==0.3.7
# see https://github.com/Hironsan/asari/issues/9#issuecomment-695706645
!pip install Janome==0.3.7
Requirement already satisfied: Janome==0.3.7 in /usr/local/lib/python3.6/dist-packages (0.3.7)
データの準備¶
感情分析の入力として使う文章は、青空文庫の
『人形つかい』
ハンス・クリスチャン・アンデルセン Hans Christian Andersen
(矢崎源九郎訳)
からピックアップさせていただきました。
list_text = [
'この人は、この世の中で、いちばんしあわせな人にちがいありません。',
'芝居小屋もすばらしいし、お客さんもすばらしい人たちでした。',
'もし中世の時代だったら、おそらく、火あぶりにされたでしょうよ。',
'みんなのうるさいことといったら、まるで、ハエがびんの中で、ブンブンいっているようでした。',
'われわれ人間が、こういうことを考えだすことができるとすれば、われわれは、地の中にうめられるまでに、もっと長生きできてもいいはずだが'
]
asari¶
Source code: asari
手法:
scikit-learn のみ利用
文章を tf-idf (term frequency–inverse document frequency) でベクトル表現に変換し、それを線形カーネルのサポートベクトルマシンを使って分類問題として文章がポジティヴかネガティヴかを判定している。
Deep Learning モデルである BERT による予測と遜色ない性能をしめしたとのこと。
どのトレーニングデータセットを使って学習したかが不明なので、どういった種類の文章で適切に判定できるかが不明。
ライセンス: MIT
%%capture capt
# シンプルな動作確認
from asari.api import Sonar
sonar = Sonar()
res = sonar.ping(text="広告多すぎる♡")
res
list(map(sonar.ping, list_text))
[{'classes': [{'class_name': 'negative', 'confidence': 0.10382535749585702},
{'class_name': 'positive', 'confidence': 0.896174642504143}],
'text': 'この人は、この世の中で、いちばんしあわせな人にちがいありません。',
'top_class': 'positive'},
{'classes': [{'class_name': 'negative', 'confidence': 0.035517582235360945},
{'class_name': 'positive', 'confidence': 0.964482417764639}],
'text': '芝居小屋もすばらしいし、お客さんもすばらしい人たちでした。',
'top_class': 'positive'},
{'classes': [{'class_name': 'negative', 'confidence': 0.5815274190768989},
{'class_name': 'positive', 'confidence': 0.41847258092310113}],
'text': 'もし中世の時代だったら、おそらく、火あぶりにされたでしょうよ。',
'top_class': 'negative'},
{'classes': [{'class_name': 'negative', 'confidence': 0.2692695045573754},
{'class_name': 'positive', 'confidence': 0.7307304954426246}],
'text': 'みんなのうるさいことといったら、まるで、ハエがびんの中で、ブンブンいっているようでした。',
'top_class': 'positive'},
{'classes': [{'class_name': 'negative', 'confidence': 0.050528495655525495},
{'class_name': 'positive', 'confidence': 0.9494715043444746}],
'text': 'われわれ人間が、こういうことを考えだすことができるとすれば、われわれは、地の中にうめられるまでに、もっと長生きできてもいいはずだが',
'top_class': 'positive'}]
「みんなのうるさいことといったら、まるで、ハエがびんの中で、ブンブンいっているようでした。」という文章は直感的にはネガティヴな印象であるが、ポジティヴとの判定になった。
他の例については妥当な判定が出ていそう。
oseti¶
Source code: oseti
解説記事: 日本語評価極性辞書を利用したPython用Sentiment Analysisライブラリ oseti を公開しました - Qiita
手法:
ライセンス: MIT
# シンプルな動作確認
import oseti
analyzer = oseti.Analyzer()
analyzer.analyze('天国で待ってる。')
[1.0]
list(map(analyzer.analyze, list_text))
[[0.0], [1.0], [0], [0], [1.0]]
2番めの文章「芝居小屋もすばらしいし、お客さんもすばらしい人たちでした。」
と
5番目の文章「われわれ人間が、こういうことを考えだすことができるとすれば、われわれは、地の中にうめられるまでに、もっと長生きできてもいいはずだが」
のみポジティヴ (+1) 判定で、他の文章に関しては ニュートラルの判定。
やはり、辞書ベースだと、辞書に含まれていない単語には弱いという印象。
pymlask¶
パッケージの作者は oseti と同じ。
Source code: pymlask
解説記事: ML-Askでテキストの感情分析 - Qiita
手法:
ML-Ask (eMotive eLement and Expression Analysis system) というライブラリを python で使えるようにしたパッケージ
2,100語の辞書によるパターンマッチングで{喜, 怒, 哀, 怖, 恥, 好, 厭, 昂, 安, 驚}の10種類の感情を推定
ライセンス: The BSD 3-Clause License
# シンプルな動作確認
import mlask
emotion_analyzer = mlask.MLAsk()
emotion_analyzer.analyze('彼のことは嫌いではない!(;´Д`)')
# => {'text': '彼のことは嫌いではない!(;´Д`)',
# 'emotion': defaultdict(<class 'list'>,{'yorokobi': ['嫌い*CVS'], 'suki': ['嫌い*CVS']}),
# 'orientation': 'POSITIVE',
# 'activation': 'NEUTRAL',
# 'emoticon': ['(;´Д`)'],
# 'intension': 2,
# 'intensifier': {'exclamation': ['!'], 'emotikony': ['´Д`', 'Д`', '´Д', '(;´Д`)']},
# 'representative': ('yorokobi', ['嫌い*CVS'])
# }
{'activation': 'NEUTRAL',
'emoticon': ['(;´Д`)'],
'emotion': defaultdict(list, {'suki': ['嫌い*CVS'], 'yorokobi': ['嫌い*CVS']}),
'intensifier': {'emotikony': ['´Д`', 'Д`', '´Д', '(;´Д`)'],
'exclamation': ['!']},
'intension': 2,
'orientation': 'POSITIVE',
'representative': ('yorokobi', ['嫌い*CVS']),
'text': '彼のことは嫌いではない!(;´Д`)'}
# せっかくなので、neologd 辞書を使ってみる
# mecab-ipadic-neologd のインストール先を調べる
import subprocess
cmd='echo `mecab-config --dicdir`"/mecab-ipadic-neologd"'
path = (subprocess.Popen(cmd, stdout=subprocess.PIPE,
shell=True).communicate()[0]).decode('utf-8')
emotion_analyzer = mlask.MLAsk('-d {0}'.format(path)) # Use other dictionary
list(map(emotion_analyzer.analyze, list_text))
[{'activation': 'NEUTRAL',
'emoticon': None,
'emotion': defaultdict(list, {'yorokobi': ['しあわせ']}),
'intensifier': {},
'intension': 0,
'orientation': 'POSITIVE',
'representative': ('yorokobi', ['しあわせ']),
'text': 'この人は、この世の中で、いちばんしあわせな人にちがいありません。'},
{'emotion': None, 'text': '芝居小屋もすばらしいし、お客さんもすばらしい人たちでした。'},
{'emotion': None, 'text': 'もし中世の時代だったら、おそらく、火あぶりにされたでしょうよ。'},
{'emotion': None, 'text': 'みんなのうるさいことといったら、まるで、ハエがびんの中で、ブンブンいっているようでした。'},
{'emotion': None,
'text': 'われわれ人間が、こういうことを考えだすことができるとすれば、われわれは、地の中にうめられるまでに、もっと長生きできてもいいはずだが'}]
こちらの手法も、辞書にある単語(しあわせ)があるとポジティヴと判定があるが、辞書にはないと判定が不可能。
いまいちな結果という印象。
huggingface の bert-base-japanese-sentiment¶
huggingface の bert-base-japanese-sentiment
ネガポジ判定 (ポジティヴとネガティヴの binary classification)
ライセンス: Apache-2.0 License
# 必要なライブラリのインストール
!pip install -q transformers
|████████████████████████████████| 2.1MB 8.7MB/s
|████████████████████████████████| 3.2MB 41.5MB/s
|████████████████████████████████| 890kB 52.9MB/s
?25h Building wheel for sacremoses (setup.py) ... ?25l?25hdone
%%capture capt
from transformers import BertTokenizer, BertForSequenceClassification, pipeline
tokenizer = BertTokenizer.from_pretrained("daigo/bert-base-japanese-sentiment")
model = BertForSequenceClassification.from_pretrained("daigo/bert-base-japanese-sentiment")
# シンプルな動作確認
print(pipeline("sentiment-analysis",model=model, tokenizer=tokenizer)("私は幸福である。"))
[{'label': 'ポジティブ', 'score': 0.9934489130973816}]
sentiment_analyzer = pipeline("sentiment-analysis",model=model, tokenizer=tokenizer)
list(map(sentiment_analyzer, list_text))
[[{'label': 'ポジティブ', 'score': 0.9596116542816162}],
[{'label': 'ポジティブ', 'score': 0.6044701933860779}],
[{'label': 'ポジティブ', 'score': 0.8851077556610107}],
[{'label': 'ポジティブ', 'score': 0.6943467855453491}],
[{'label': 'ポジティブ', 'score': 0.5758240222930908}]]
# 上記すべてポジティヴ判定になってしまったので、他の例でも試してみる
list(map(sentiment_analyzer, ['最悪だ', '今日は暑い', 'こんにちは', 'ふつう']))
[[{'label': 'ネガティブ', 'score': 0.9891454577445984}],
[{'label': 'ネガティブ', 'score': 0.8046908974647522}],
[{'label': 'ポジティブ', 'score': 0.9862995147705078}],
[{'label': 'ポジティブ', 'score': 0.9928306937217712}]]
用意したすべての例文すべてがポジティヴ判定になってしまったので、他の例でも試してみた。
わかりやすいネガティヴな文章は、ネガティヴと判定されるよう。
ニュートラルな文章は、ポジティヴに判定されやすい傾向がありそう。
まとめ¶
日本語文章の感情分析を簡単にできるツールを試してみました。
こういったツールを公開していただけていることに感謝ですね。
真面目に感情分析やって、もっと妥当な結果を出そうとすると、トレーニングデータセットを充実させたり、さらに工夫が必要になりそうです。
(手法ごとの感情分析の結果を定量的に評価するためのデータセット、いいのないだろうか。。。)
参考¶
解説、まとめ記事¶
感情分析日本語データセット¶
SNOW D18:日本語感情表現辞書 - 長岡技術科学大学 自然言語処理研究室
長岡技術科学大学 自然言語処理研究室
約2,000表現を収録し、各表現に対して我々が独自に定義した48分類の感情を付与