アラカン"BOKU"のITな日常

文系システムエンジニアの”BOKU”が勉強したこと、経験したこと、日々思うことを書いてます。

試行錯誤その5:自然言語処理の基本はまず品詞。初心に返って頭を整理してみよう。

前回で、それまでのやり方をちょっと見直そうと決めました。

arakan-pgm-ai.hatenablog.com

 

とにかく、偶然のみにまかせて何とかしようという発想はすてる必要があります。

 

まず、品詞・・をもうちょっと真面目にとらえないいけない。

 

ということですね。

 

名詞と形容詞みたいな自立語だけを対象にする・・みたいな、ざっくりすぎるやり方は無理があります。

 

今回は、瀕死の整理と今後の作戦を考えてみます。

 

まずは品詞の整理から

 

ざっくり整理すると、こんな感じかな。

分類1 分類2 品詞 ざっくりした用途
自立語 活用する 動詞 「走る」「消える」のように動作や変化を表すほか、「ある」「違う」「匹敵する」のように存在や状態を表すものも含まれる。
自立語 活用する 形容詞 大小・長短・高低・新旧・好悪・善悪・色などの意味を表す。
自立語 活用する 形容動詞 「不謹慎である」のように「~である」をつけることができたり、「堂々たれ」のような命令形になる
自立語 活用なし 名詞 物体・物質・人物・場所など具体的な対象を指示する
自立語 活用なし 連体詞 「あの」「我が」「いわゆる」「大きな」「あらぬ」「たいした」のような表現。形容詞に近い。
自立語 活用なしい 副詞 「よく」「頻繁に」「たやすく」「すぐ」みたいな表現。主に修飾する言葉。
自立語 活用なし 接続詞 前後の文脈の関係を表す。「だから」「けれども」「しかし」など
自立語 活用なし 感動詞 感動、応答、呼びかけを表す。「ああ」「はい」「いいえ」「おはよう」「えい」など
付属語 活用する 助動詞 動詞や動詞系の助動詞などについて、時制や受身などを表す。「あります」の「ます」とか、「やりたい」の「たい」とか
付属語 活用なし 助詞 単語に付属し関係を表したり、対象を表したりする。「僕が」の「が」とか、「これより」の「より」とか、「これだけ」の「だけ」とか。

 

 さて、ネガポジを考えるにあたって、どういう単位で考えるべきか?の話です。

 

例えば、「君を後悔させなかった」と「君を後悔させた」という2つ文章です。

 

全体としては前者がポジティブ、後者はネガティブです。

 

これをそれぞれjanomeで分解するとこうなります。

 

君:名詞,代名詞,一般,*
を:助詞,格助詞,一般,*
後悔:名詞,サ変接続,*,*
さ:動詞,自立,*,*
せ:動詞,接尾,*,*
なかっ:助動詞,*,*,*
た:助動詞,*,*,*

 

君:名詞,代名詞,一般,*
を:助詞,格助詞,一般,*
後悔:名詞,サ変接続,*,*
さ:動詞,自立,*,*
せ:動詞,接尾,*,*
た:助動詞,*,*,*

 

「君を後悔させ」までは同じで、続く言葉が「た」ならポジティブ、「なかった」ならネガティブということなんですね。

 

ところが、前回までのアプローチだと、名詞・動詞・形容詞などの一部の自立語にあたる単語のスコアだけで判断しようとしていたので、「君」「後悔」「さ」「せ」だけが対象・・あれ・・両方同じです。

 

これでは確率50%以上になるわけないですね。

 

助動詞までふくめても「なかっ」があるかどうかで単語レベルでネガポジを反転させるとか・・うーーん・・相当無理なことをしようとしてたなとわかります。

 

どういう単位でネガポジ判断をする必要があるのか?

 

じゃあ、ネガポジ判断がある程度の精度でできる文章の切り方はどうなるのか?

 

これを考えてみたいと思います。

 

さっきの例でいけば。

 

「君を後悔させなかった」は、「君を/後悔させなかった」。

 

「君を後悔させた」は、「君を/後悔させた」。

 

であることは明らかです。

 

だって、後悔という名詞だけでは判断できませんから。

 

「後悔させなかった」と「後悔させた」という単位で、はじめてネガポジ判断ができることになります。

 

なるほど・・。

 

そのセンテンスの切れ目はむしろ「助詞」「助動詞」などの付属語なんですね。

 

じゃあ、こういう人がネガ・ポジ判断しやすい単位で文章を分割し、その単位で辞書を生成して、予測するようにするべきではないか。

 

この考え方を軸にすると面白そうです。

 

オリジナルTokenizerのサンプルを作ってみました

 

そうすると、さきほどの考え方で納得いく分け方ができるツール・・Tokenizer・・が必要ですね。

 

さっそく、たたき台を作ってみます。

 

まずは、動作確認用の骨格だけ。

 

まずは、コードです。

from janome.tokenizer import Tokenizer
import re

def boku_tokenizer(l_in):
    b_w = re.compile(r'助詞|助動詞|接続詞')
    b_wj = re.compile(r'助動詞')
    b_wk = re.compile(r'記号')
    tok = Tokenizer()
    l_o = tok.tokenize(l_in)
    l_work = []
    b_threw = False
    for n in l_o:
        if(b_w.match(n.part_of_speech)):
            l_work.append(n.surface)
            c_work = ''.join(l_work)
            if(b_wj.match(n.part_of_speech)):
                b_threw = True
            else:    
                print(c_work)
                l_work = []
        else:
            if(b_threw):
                print(c_work)
                l_work = []
                b_threw = False
            if not(b_wk.match(n.part_of_speech)):
                l_work.append(n.surface)
    c_work = ''.join(l_work)
    print(c_work)

 

ルールは、こんな感じです。

  • 助詞と助動詞と接続詞以外なら、単語(n.surface)を連結する。
  • ただし、記号なら、その文字は連結しない
  • 助詞なら、その単語を連結して出力
  • 助動詞なら一旦連結してマーキングして、助動詞以外がでてきたときに出力

 

なんで、こうしているかというと、助動詞は「なかっ」と「た」みたいに、複数連続して登場する場合があるからです。

 

2018/02/10 追記

>いろいろ、やっていると助詞が重なるパターンもありました。

>「b_wj = re.compile(r'助動詞')」 のところは、 「b_wj = re.compile(r'助詞|助動詞')」>にして今はやってます。

 

とりあえず、これで処理してみます。

 

boku_tokenizer('君を後悔させた')

君を
後悔させた

 

boku_tokenizer('君を後悔させなかった') 

君を
後悔させなかった

 

あ・・、いい感じです。

 

もう少し、複雑な文書もやってみます。

boku_tokenizer('怒られるからダメではなくて、しつけやマナーはしっかりと教えましょう')

怒られるから
ダメではなくて
しつけや
マナーは
しっかりと
教えましょう

 

今度は、「」でくくってみます。

boku_tokenizer('「怒られるからダメ!」ではなくて、しつけやマナーはしっかりと教えましょう')

 怒られるから
ダメではなくて
しつけや
マナーは
しっかりと
教えましょう

 

今度は、しかし・・とかで文脈の切り替えをしてみます。

>boku_tokenizer('君は僕の大切な友達だ。しかし、その行いは容認できない。')

君は
僕の
大切な
友達だ
しかし
その行いは
容認できない

 

いいじゃないですか。

 

なんとなく、単純に形態素解析しただけよりは、精度の高いネガポジ判断ができそうな分け方にはなってますね。

 

しばらく、この方向ですすんでみようと思います。

 

まずは、やってみないとわかんないですし。