Python入門トップページ


単語感情極性対応表を用いた感情分析:目次

  1. MeCab で形態素解析を実行する
  2. 単語感情極性対応表を確認する
  3. 見出し語の重複を無視して作成した辞書で感情を分析する
  4. 見出し語の重複を考慮した辞書を作成する
  5. 見出し語の重複を考慮して作成した辞書で感情を分析する
  6. 読みをカタカナに変換した辞書でスコアを取得する
  7. 見出し語と読みの情報を利用して感情を分析する

Python で感情分析をしてみよう

単語感情極性対応表を用いた感情分析

単語感情極性対応表を確認する

次に,東京工業大学の奥村・船越研究室 (https://lr-www.pi.titech.ac.jp/wp/) で公開されている単語感情極性対応表をダウンロードします.このページ (http://www.lr.pi.titech.ac.jp/~takamura/pndic_ja.html) から日本語の辞書データ (pn_ja.dic) をダウンロードしてください.ダウンロードしたデータは dic フォルダを作成してその中に格納することにします.なお,この単語感情極性対応表の参考文献は次の通りです.

  • 高村大也, 乾孝司, 奥村学, "スピンモデルによる単語の感情極性抽出", 情報処理学会論文誌ジャーナル, Vol.47 No.02 pp. 627--637, 2006.
  • Hiroya Takamura, Takashi Inui, Manabu Okumura, "Extracting Semantic Orientations of Words using Spin Model", In Proceedings of the 43rd Annual Meeting of the Association for Computational Linguistics (ACL2005), pages 133--140, 2005.

dic フォルダに設置した pn_ja.dic ファイルの中身をテキストエディタなどで確認します.文字コードが utf-8 ではなく Shift-JIS になっていることに注意してください.各行には「見出し語」「読み」「品詞」「感情極性実数値」が記録されており,それぞれがコロン「:」で区切られています.さらに,感情極性実数値は+1から-1までの値になっていることがわかります.「優れる」や「良い」という見出し語は良い印象を持つ positive な単語であり,「死ぬ」や「悪い」という見出し語は悪い印象を持つ negative な単語であると言えます.

dic/pn_ja.dic
優れる:すぐれる:動詞:1
良い:よい:形容詞:0.999995
喜ぶ:よろこぶ:動詞:0.999979
褒める:ほめる:動詞:0.999979
めでたい:めでたい:形容詞:0.999645
賢い:かしこい:形容詞:0.999486

...(中略)...

大尉:たいい:名詞:0.000344221
婦徳:ふとく:名詞:0.000205878
用務:ようむ:名詞:0.00012227
救貧:きゅうひん:名詞:3.01237e-05
漏斗:ろうと:名詞:0
夜曲:やきょく:名詞:0
冬籠る:ふゆごもる:動詞:0
沢庵:たくわん:名詞:0
他称:たしょう:名詞:0
第三人称:だいさんにんしょう:名詞:0
セレナーデ:セレナーデ:名詞:0
巨体:きょたい:名詞:0
巨躯:きょく:名詞:0
細螺:きしゃご:名詞:0
忌明け:きあけ:名詞:0
ウイーク エンド:ウイーク エンド:名詞:0
温突:オンドル:名詞:0
州浜:すわま:名詞:0
眇める:すがめる:動詞:0
眇む:すがむ:動詞:0
白子:しろこ:名詞:0
週末:しゅうまつ:名詞:0
小夜曲:さよきょく:名詞:0
啄木鳥:けらつつき:名詞:0
新設:しんせつ:名詞:-4.80247e-05
公方:くぼう:名詞:-8.89323e-05
銃傷:じゅうしょう:名詞:-0.000100071
お母さん:おかあさん:名詞:-0.000145459
ちえ袋:ちえぶくろ:名詞:-0.00015696

...(中略)...

ない:ない:形容詞:-0.999882
浸ける:つける:動詞:-0.999947
罵る:ののしる:動詞:-0.999961
ない:ない:助動詞:-0.999997
酷い:ひどい:形容詞:-0.999997
病気:びょうき:名詞:-0.999998
死ぬ:しぬ:動詞:-0.999999
悪い:わるい:形容詞:-1

Python の pandas でこのファイルを読み込んでみましょう.文字コードが sjis であること,カンマ (,) ではなくコロン (:) で区切られていることに注意します.また,見出し行がないことから列名も指定します.


import pandas as pd
import os

# 単語感情極性対応表
path_dic = os.path.sep.join(['dic', 'pn_ja.dic'])
df_pn = pd.read_csv(path_dic, encoding="sjis", sep=":", names=["lemma", "reading", "pos", "score"])
df_pn
2024-sentiment-01

上の出力結果から 55,125件の見出し語が登録されていることがわかります.データフレームから見出し語の列を抽出,さらにリスト化して,その個数を調べます.

見出し語(原型:lemma)が何個あるか
lemma = df_pn["lemma"].tolist()
print(len(lemma))
55125

リストから集合を作成すると重複を除くことができます.重複を除くと 52,671件に減少しました.

集合を作成して重複を除く
lemma_set = set(lemma)
print(len(lemma_set))
52671

重複した見出し語の個数をカウントします.

重複の個数
print(len(lemma) - len(lemma_set))
2454

2,454件の重複が確認できました.どのような見出し語に重複があるのかを確認します.このためには Pandas の groupby を用いて見出し語 (lemma) でグループ化し,その個数をカウントします.


sorted_df = df_pn.groupby('lemma')['score'].count().reset_index()
sorted_df = sorted_df.sort_values(by=['score'], ascending=[False])
sorted_df[sorted_df.score > 1]
2024-sentiment-02

2,050個の見出し語については重複して登録されていることがわかります.たとえば見出し語「ホーム」には11個の感情極性実数値が登録されているわけです.この詳細は確認してくべきでしょう.データフレームから lamma に "ホーム" と登録された行をすべて抽出します.すると,読みの「ホームラン」,「ホームスパン」,「ホーム」などがすべて見出し語「ホーム」として登録されていることがわかりました.これらの取り扱いをどうするかは後ほど検討することにします.


df_pn[df_pn.lemma == "ホーム"]
2024-sentiment-03

「ホームラン」の「ラン」や「ホームスパン」の「スパン」は登録されていませんが,「ホームドラマ」の「ドラマ」や「ホームヘルパー」の「ヘルパー」は個別に登録されていることも確認できます.


print(df_pn[df_pn.lemma == "ラン"])
Empty DataFrame
Columns: [lemma, reading, pos, score]
Index: []

print(df_pn[df_pn.lemma == "スパン"])
Empty DataFrame
Columns: [lemma, reading, pos, score]
Index: []

print(df_pn[df_pn.lemma == "ドラマ"])
      lemma reading pos     score
14874   ドラマ     ドラマ  名詞 -0.188471

print(df_pn[df_pn.lemma == "ヘルパー"])
      lemma reading pos    score
20616  ヘルパー    ヘルパー  名詞 -0.25243

さらに,重複のあった「大和」,「太刀」,「頭」,「猿」についてもどのような重複データとして登録されているか確認します.また,「ホームラン」の読みはカタカナで登録されていますが,「やまとなでしこ」の読みはひらがなで登録されていることにも注意してください.


df_pn[df_pn.lemma == "大和"]
2024-sentiment-04

df_pn[df_pn.lemma == "太刀"]
2024-sentiment-05

df_pn[df_pn.lemma == "頭"]
2024-sentiment-06

df_pn[df_pn.lemma == "猿"]
2024-sentiment-07

さらに,どのような品詞が登録されているかを確認します.すると圧倒的に名詞が多く登録されていることがわかりました.


df_pn.groupby('pos')['score'].count()
pos
副詞      1207
助動詞        2
動詞      4252
名詞     48999
形容詞      665
Name: score, dtype: int64

続いて,感情極性実数値の平均値など基本統計量を確認します.これは Pandas の describe() を使うと良いでしょう.この結果,感情極性実数値の平均値がゼロではなくおよそ -0.32 であること,多くの見出し語の感情極性実数値は負の値になっていることに注意してください.


df_pn['score'].describe()
count    55125.000000
mean        -0.319764
std          0.382738
min         -1.000000
25%         -0.522353
50%         -0.339964
75%         -0.176277
max          1.000000
Name: score, dtype: float64

感情極性実数値がどのような分布になっているかも確認しておくべきでしょう.これは ydata-profiling でレポートを作成すると簡単に確認できます.

ydata-profiling でレポートを作成
from ydata_profiling import ProfileReport
profile = ProfileReport(df_pn)
profile.to_file("pn_report.html")

カレントフォルダに pn_report.html というファイルが出力されているはずなので,その中身を確認するとよいでしょう.この結果,全体の 90.7% もが負の値になっていることがわかります.さらに次のヒストグラムからは,-0.9から-0.5の範囲に多くのデータがある一方で,+0.5から+0.9の範囲にはほとんど存在しないこともわかります.これら結果からわかることは,感情極性実数値が正である見出し語が圧倒的に少ない(およそ9.3%である)ことから,正か負かという情報だけで positive/negative の判定をすると多くの場合で negative という結果になってしまうということです.

2024-sentiment-08

続いて,見出し語から感情極性実数値が得られるように辞書を作成します.ただし,現段階では「ホーム」や「大和」など重複のある見出し語についての処理には潜在的な問題があることにも注意してください.重複を無視すれば次の方法で簡単にデータフレームから辞書を作成することができます.

辞書の作成
dic_lemma = df_pn.set_index('lemma')['score'].to_dict()

作成した辞書を表示してみます.(ただし,非常に多くの結果が表示されるので実行には注意してください.)


print(dic_lemma)
{'優れる': 1.0, '良い': 0.999995, '喜ぶ': 0.999979,
...(中略)...
'ホーム': -0.408128,
...(中略)...
'大和': -0.571956,
...(中略)...
'病気': -0.999998, '死ぬ': -0.999999, '悪い': -1.0}

上の辞書 dic_lemma から「ホーム」の値だけを抽出します.


dic_lemma['ホーム']
-0.408128

データフレームから見出し語「ホーム」の行をすべて抽出します.辞書 dic_lemma に「ホーム」として格納されている値は最後の「ホームヘルパー」の値 -0.408128 だけであることに注意してください(この問題は次のページ以降で処理します).


df_pn[df_pn.lemma == "ホーム"]
2024-sentiment-09

さらに理解を深めるために,読みでもグループ化してどの程度の重複があるかを確認しておきます.読みでは 6,063件の重複があり,中でも「しょう」という読みでは45件の見出し語が登録されていることがわかります.


sorted_df = df_pn.groupby('reading')['score'].count().reset_index()
sorted_df = sorted_df.sort_values(by=['score'], ascending=[False])
print(sorted_df[sorted_df.score > 1])
      reading  score
15391     しょう     45
13840       し     40
6499       かん     37
7171        き     34
19384      そう     33
...       ...    ...
2079      いへん      2
34097     みけん      2
22207   ちょうあい      2
10206     けっき      2
15483  しょうしゅつ      2

[6063 rows x 2 columns]

「しょう」という読みでどのような見出し語が登録されているか確認します.


print(df_pn[df_pn.reading == "しょう"])
      lemma reading pos     score
11        賞     しょう  名詞  0.998943
115       昌     しょう  名詞  0.996219
509       正     しょう  名詞  0.990394
767       奨     しょう  名詞  0.987421
993       勝     しょう  名詞  0.983870
1438      祥     しょう  名詞  0.975947
1907      笑     しょう  名詞  0.963530
2088      匠     しょう  名詞  0.953358
3080      捷     しょう  名詞  0.264843
5625      性     しょう  名詞 -0.026737
7477      沼     しょう  名詞 -0.087891
14807     廠     しょう  名詞 -0.187703
16261     庄     しょう  名詞 -0.203384
16642     晶     しょう  名詞 -0.207766
17346     松     しょう  名詞 -0.215653
18159     照     しょう  名詞 -0.224491
21181     将     しょう  名詞 -0.258830
22097   背負う     しょう  動詞 -0.270019
22110     昭     しょう  名詞 -0.270113
25526     宵     しょう  名詞 -0.312423
26771     升     しょう  名詞 -0.329012
27777     省     しょう  名詞 -0.342514
29073     渉     しょう  名詞 -0.360132
31167     商     しょう  名詞 -0.388045
31946     荘     しょう  名詞 -0.397786
34975     尚     しょう  名詞 -0.435942
36396     詔     しょう  名詞 -0.453293
37903     笙     しょう  名詞 -0.473510
37920     象     しょう  名詞 -0.473671
40299     彰     しょう  名詞 -0.506979
41250     証     しょう  名詞 -0.521029
42343     小     しょう  名詞 -0.538430
42501     昇     しょう  名詞 -0.540795
42978     醤     しょう  名詞 -0.548599
45147     装     しょう  名詞 -0.588353
45567     章     しょう  名詞 -0.596776
46178     床     しょう  名詞 -0.609430
47049     称     しょう  名詞 -0.630153
48521     掌     しょう  名詞 -0.676449
48659     妾     しょう  名詞 -0.681568
49666     鉦     しょう  名詞 -0.725421
50529     焼     しょう  名詞 -0.780068
51106     鐘     しょう  名詞 -0.825152
52845     症     しょう  名詞 -0.985740
55014     傷     しょう  名詞 -0.998220

重複の多かった「そう」についても同様に確認しておきましょう.


print(df_pn[df_pn.reading == "そう"])
      lemma reading pos     score
402       聡      そう  名詞  0.991917
480       壮      そう  名詞  0.990775
9216      早      そう  名詞 -0.119214
12524     艘      そう  名詞 -0.161492
17818     操      そう  名詞 -0.220665
26017     宋      そう  名詞 -0.318915
29367     蒼      そう  名詞 -0.364092
31913     双      そう  名詞 -0.397465
32276     槍      そう  名詞 -0.402230
32482     宗      そう  名詞 -0.405082
32873     相      そう  名詞 -0.410390
33561     槽      そう  名詞 -0.418203
33679     桑      そう  名詞 -0.419539
34658     奏      そう  名詞 -0.432226
40388     叢      そう  名詞 -0.508289
41026     瘡      そう  名詞 -0.517506
41151     想      そう  名詞 -0.519655
41224     窓      そう  名詞 -0.520621
41367     創      そう  名詞 -0.522894
41786     倉      そう  名詞 -0.529372
42228     藻      そう  名詞 -0.536728
42549     荘      そう  名詞 -0.541712
44463     箏      そう  名詞 -0.575231
46611     装      そう  名詞 -0.619199
47252     相      そう  名詞 -0.636353
47409     喪      そう  名詞 -0.640564
48157     葬      そう  名詞 -0.663802
48912     層      そう  名詞 -0.690597
50158     霜      そう  名詞 -0.754495
50647    沿う      そう  動詞 -0.789147
50918     巣      そう  名詞 -0.810283
51329     僧      そう  名詞 -0.847341
51940     草      そう  名詞 -0.946003

目次に戻る