極性辞書を自前で作れるか試してみた


#極性（辞書）とは
単語は陽(positive)な印象と、陰(negative)な印象を持つ。
その陽や陰が極性であり、単語ごとに極性を定義してあるものが、
極性辞書というもの。

↓参照
http://diary.overlasting.net/2012-08-28-1.html

#日本語の極性辞書
すごいですね。。。偉大な研究だと思います。
感情分析を実装してみた系は以下の辞書を使われている事例が多いようです

http://www.cl.ecei.tohoku.ac.jp/index.php?Open%20Resources%2FJapanese%20Sentiment%20Polarity%20Dictionary

http://www.lr.pi.titech.ac.jp/~takamura/pndic_ja.html

#極性辞書を利用したいシーン
今のところ極性辞書は感情分析などに使われることが多いようです。
例えば以下のような場合、なんとなく一つ目がポジティブな文章で、
二つ目名文章が普通、三つ目の文章はネガティブな印象を受けると思います。

- 今日の大阪の天気は晴れ
- 今日の大阪の天気は曇り
- 今日の大阪の天気は雨

#極性辞書ちらみしてみて。。。
うーん、私なんかが想像がつかないような緻密な理論によって、極性がつけられていると思います。
ただ、思てたんとは違う気がする。。。

##単語感情極性対応表(pn_ja.dic)
でどういう単語がポジティブで、どういう単語がネガティブか見てみます。
一番ポジティブは `優れる:すぐれる:動詞:1`
一番ネガティブは `悪い:わるい:形容詞:-1`

自転車は `自転車:じてんしゃ:名詞:-0.575164` ネガティブな極性が付いています。

自転車ってネガティブなんすかね？

##晴れは万人にとって、いついかなる場合でもポジティブか？
「晴れ」ってうれしいんじゃないのと思うかもしれませんが、本当でしょうか？

- ものすごい日照り続きで、そろそろ雨がふらないと、農作物に影響が出るような場合、晴れはうれしいか？
- （上記の場合だとむしろ雨の方がうれしいのでは？）
- 野球部の同級生がいうには、「晴れより曇りの方が練習がしんどくなくてよい」とのこと
- （屋外練習がなくなる雨が一番好ましいのでは。。。）

雑な言い方でまとめると、TPOでケースバイケースな感じ

#とりあえず極性辞書的なものを作ってみることにします
ちょっと手を動かさないとイメージがつかないので、実験用のコードを書いてみます


きっかけになったサイトはこちら
（本当にありがとうございます）
http://catindog.hatenablog.com/entry/2017/04/17/123655

#仮組
##PGの時間です

以下のような日本語と極性を想定します。
晴れのときは１ポジティブ、０は普通、-1がネガティブです

- 本日の大阪の天気は晴れです',1
- 本日の大阪の天気は曇りです',0
- 本日の大阪の天気は雨です',-1

天気の状態（晴れ、曇、雨）以外は同じ日本語ですので、形態素解析にかけて、その後で、ポジティブ/ネガティブを算出した場合、
晴れがポジティブ
曇りとその他の単語が普通
雨がネガティブ

になっていればOKです


```python:polarlike.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Feb 13 02:04:20 2019

@author: hoge
"""

import util
import numpy as np
import numba
from sklearn.feature_extraction.text import CountVectorizer

data = np.array([
        ['本日の大阪の天気は晴れです',1],
        ['本日の大阪の天気は曇りです',0],
        ['本日の大阪の天気は雨です',-1],        
        ])

@numba.jit
def cvectizer(docs):
    vectizer = CountVectorizer(analyzer=util.terms)
    x = vectizer.fit_transform(docs)
    return x,vectizer

@numba.jit
def calcPosiNega(x,ratings):
    row_c,col_c = x.shape
    calcPosiNegaByRow = np.zeros((row_c,col_c))
    calcPosiNegaByCol = np.zeros(col_c)
    for row,rate in zip(range(row_c),ratings):
        for col in range(col_c):
            ans = rate * np.log10(x[row,col] / np.sum(x[row,:]) +1 )
            calcPosiNegaByRow[row][col] = ans
    calcPosiNegaByCol = np.sum(calcPosiNegaByRow,axis=0)
    return calcPosiNegaByCol



x,vectizer = cvectizer(data[:,0])


"""
出現回数(ベクトル)の確認
x.toarray()
array([[1, 1, 1, 0, 1, 0],
       [1, 1, 0, 1, 1, 0],
       [1, 1, 0, 0, 1, 1]], dtype=int64)
"""

"""
ベクトル算出時の単語
vectizer.get_feature_names()
['大阪', '天気', '晴れ', '曇り', '本日', '雨']
"""

#単語ごとの極性を算出する
ratings = data[:,1].astype(np.int)
posinega_arr = calcPosiNega(x,ratings)

polar_dict=np.array((vectizer.get_feature_names(),posinega_arr)).T
"""
print(polar_dict)
[['大阪' '0.0']
 ['天気' '0.0']
 ['晴れ' '0.09691001300805642']
 ['曇り' '0.0']
 ['本日' '0.0']
 ['雨' '-0.09691001300805642']]
"""
```

差異がある単語の部分だけ、算出されてます


```python:util.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Feb 13 02:24:58 2019

@author: hoge
"""

import MeCab

PART_OF_SEARCH=("名詞","形容詞","動詞","形容動詞")

def _split_to_word(text,to_stem=False):
    tagger = MeCab.Tagger('mecabrc')
    mecab_result = tagger.parse(text)
    words_info = mecab_result.split('\n')
    words = []
    for info in words_info:
        if info == 'EOS' or info =='':
            break
        info = info.replace('\t',',')
        info_elms = info.split(',')
        
        if info_elms[1] not in PART_OF_SEARCH:
            continue
        if to_stem and info_elms[7] != '*':
            words.append(info_elms[7])
        else:
            words.append(info_elms[0])
    return words

#基本形を返す    
def stems(text):
    stems = _split_to_word(text,to_stem=True)
    return stems

#表層形を返す
def terms(text):
    terms = _split_to_word(text,to_stem=False)
    return terms

if __name__ == '__main__':
    text = "メロスは激怒した。必ず、かの邪智暴虐の王を除かなければならぬと決意した。"
    print(stems(text))
    print(terms(text))

```


#まとめ
いったん手作りのデータで極性が出そうなことが分かりました。

#積残し
##ドメインを決める
ここでいうドメインは極性辞書を作るサイトやドキュメントの類を絞るという意味です。
例えば
①「テレビ」という単語がすごくポジティブに使われているサイト　と
②「テレビ」という単語がすごくネガティブに使われているサイト　があって

サイト内で使われる単語は同じでも極性は違うと思います。

要するに、サイトやドキュメントのカテゴリを絞りましょうという話です。
こういう表現が適切かどうかはわかりませんが、
ローカル極性辞書　や　ドメイン極性辞書　というイメージです

##極性の考え方
今回は晴れとか、雨とかに1,0,-1を手でつけました。
極性辞書作るのにここを手作りにするのは、非常にもったいないと思います。

なのでサイトのレビューの点数（星の数）を正規化して使うのも良さそうです。
インバランスなデータになりそうですが、それをそのまま受け入れてモデルを作っても、
あまり芳しい結果ではありませんでした。

あと、あまりに長い文章と、短い文章を混ぜるのも、サンプル数が少ないようだと検討する必要があります。

例）
[動かない、最悪,-1]
みたいな文章は、「動かない」と「最悪」に-1が割り振られてしまいますので、すごく強い極性がでます
逆に
[いろいろ試してみた結果、インストールとアンインストールと、環境変数を調整してネットでググりまくったけど動きませんでした、最悪,-1]
みたいな文章は最悪に割り当てられる、極性は前者の例より小さくなります

##前処理を頑張る
- ソースを見てお気付きの方もいると思いますが、今回品詞を絞っているが、絞り方が正しいか？
- Mecab 以外の形態素分析の仕組みで試してみる
- ユーザー辞書をつくる
- ストップワードを考える
等