LoginSignup
103
82

More than 3 years have passed since last update.

Python で日本語文章の感情分析を簡単に試す (google colab で試す)

Last updated at Posted at 2020-08-08

こちらの記事は少し古くなっています。修正した記事を下記の URL へ移転しました。

Open In Colab

Python で日本語文章の感情分析を簡単に試す (with google colab)

感情分析を簡単に試すときに使えるツール一覧

試してみたツールを箇条書きにして以下に示します。

必要なライブラリのインストール

%%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

データの準備

感情分析の入力として使う文章は、青空文庫の

『人形つかい』

ハンス・クリスチャン・アンデルセン Hans Christian Andersen
(矢崎源九郎訳)

からピックアップさせていただきました。

list_text = [
             'この人は、この世の中で、いちばんしあわせな人にちがいありません。',
             '芝居小屋もすばらしいし、お客さんもすばらしい人たちでした。',
             'もし中世の時代だったら、おそらく、火あぶりにされたでしょうよ。',
             'みんなのうるさいことといったら、まるで、ハエがびんの中で、ブンブンいっているようでした。',
             'われわれ人間が、こういうことを考えだすことができるとすれば、われわれは、地の中にうめられるまでに、もっと長生きできてもいいはずだが'
]

asari

  • Source code: asari
  • 解説記事: 日本語 Sentiment Analyzer を作ってパッケージ化した話 - Ahogrammer
  • 手法:
    • 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

# シンプルな動作確認
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 と同じ。

# シンプルな動作確認
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

# 必要なライブラリのインストール
!pip install -q transformers
%%capture capt

from transformers import AutoTokenizer, AutoModelForSequenceClassification
from transformers import pipeline

tokenizer = AutoTokenizer.from_pretrained("daigo/bert-base-japanese-sentiment")

model = AutoModelForSequenceClassification.from_pretrained("daigo/bert-base-japanese-sentiment")
# シンプルな動作確認

print(pipeline("sentiment-analysis",model="daigo/bert-base-japanese-sentiment",tokenizer="daigo/bert-base-japanese-sentiment")("私は幸福である。"))
[{'label': 'ポジティブ', 'score': 0.9843042492866516}]
sentiment_analyzer = pipeline("sentiment-analysis",model="daigo/bert-base-japanese-sentiment",tokenizer="daigo/bert-base-japanese-sentiment")

list(map(sentiment_analyzer, list_text))
[[{'label': 'ポジティブ', 'score': 0.6794141530990601}],
 [{'label': 'ポジティブ', 'score': 0.972648024559021}],
 [{'label': 'ポジティブ', 'score': 0.8007588386535645}],
 [{'label': 'ポジティブ', 'score': 0.7873095870018005}],
 [{'label': 'ポジティブ', 'score': 0.9143434166908264}]]
# 上記すべてポジティヴ判定になってしまったので、他の例でも試してみる

list(map(sentiment_analyzer, ['最悪だ', '今日は暑い', 'こんにちは', 'ふつう']))
[[{'label': 'ネガティブ', 'score': 0.9896144866943359}],
 [{'label': 'ネガティブ', 'score': 0.8293251991271973}],
 [{'label': 'ポジティブ', 'score': 0.9862995147705078}],
 [{'label': 'ポジティブ', 'score': 0.9928306937217712}]]

用意したすべての例文すべてがポジティヴ判定になってしまったので、他の例でも試してみた。

わかりやすいネガティヴな文章は、ネガティヴと判定されるよう。

ニュートラルな文章は、ポジティヴに判定されやすい傾向がありそう。

まとめ

日本語文章の感情分析を簡単にできるツールを試してみました。

こういったツールを公開していただけていることに感謝ですね。

真面目に感情分析やって、もっと妥当な結果を出そうとすると、トレーニングデータセットを充実させたり、さらに工夫が必要になりそうです。

(手法ごとの感情分析の結果を定量的に評価するためのデータセット、いいのないだろうか。。。)

参考

解説、まとめ記事

感情分析日本語データセット

103
82
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
103
82