ブログ名

【第13回】5W1H抽出AI KNPを用いた手法の検討

KNPを用いた手法

KNPは地名や人名を正確に分類できるためWhen/Where抽出する時に役立ちますが、
係り受け解析は文節ではなくチャンクごとに分類するCaboChaの方が正確であることが多いです。
そのため、When/Whoの抽出にはKNPを、Why/What/Howの抽出にはCaboChaを使用することで、今までで最も正確に5W1Hを抽出することが可能になりました。
以下にソースコードを示します。

ソースコード

python
import CaboCha
from pyknp import KNP
import re

sentence = 'きょうの会見に合わせたかのように宮迫さんがユーチューバーとしてまーデビューされました'

When = []
Where = []
What = []
Why = []
Who = []
How = []
c = CaboCha.Parser('-d /usr/local/lib/mecab/dic/mecab-ipadic-neologd')

words = []
poss = []
chunkId = [] 
toId = []
ID = -1
scores = []
howId = []


nani = ['は','が','を','の'] # Whatの後に続く助詞
naze =['だから', 'それで', 'そのため', 'このため', 'そこで', 'したがって', 'ゆえに', 'それゆえに','から','んで','ため']# Whyの後に続く接続助詞


tree =  c.parse(sentence) 
knp = KNP(option='-tab')     # Default is JUMAN++. If you use JUMAN, use KNP(jumanpp=False)
result = knp.parse(sentence)

for i in range(0, tree.size()):
    token = tree.token(i)
    # 単語を取得
    word = token.surface
    words.append(word) # 文字をスタック
    # 品詞を取得
    pos = token.feature.split(",")
    poss.append(pos) # 品詞をスタック
    #チャンクIDを取得
    if token.chunk != None:
            ID += 1
    chunkId.append(ID)
    # かかり先IDを取得
    if token.chunk != None:
        ID2 = token.chunk.link

    toId.append(ID2)
        # スコアを取得
    if token.chunk != None:
           score  = token.chunk.score
    scores.append(score)


for mrph in result.mrph_list(): # 各形態素へのアクセス
    
    so_f = re.split("[-:]", mrph.imis) # feature分割
    
    if mrph.bunrui == '地名' or '場所' in so_f:
        Where.append(mrph.midasi)
    
    elif '人' in so_f or '人名' in so_f or mrph.bunrui == '人名':
        Who.append(mrph.midasi)
        
for bnst in result.bnst_list(): # 各文節へのアクセス2
    setu_f = re.split("[><]", bnst.fstring)
    del setu_f[::2]
    if '時間' in setu_f:
        When.append("".join(mrph.midasi for mrph in bnst.mrph_list()))
    
num = len(words)-1
while num > -1:
    
##Why##
    for c in naze:  
        if words[num] == c: #続く助詞がWhyの後に続くものの場合
            Why.append(words[num])
            nowId = chunkId[num] # 最初のチャンクIDを保存
        
            while num>0:
            
                if chunkId[num-1] != nowId and toId[num-1] > nowId and words[num-1] != '(': #今のチャンクIdが最初のIdでなく, かかり先Idが最初のId出ない
                    break
                num -=1
                Why.insert(0,words[num])

        
    if words[num] == 'に' and words[num-1] == 'ため':
        words.insert(num,'Why)')
        nowId = chunkId[num] # 最初のチャンクIDを保存
        
        while num>0:
            
            if chunkId[num-1] != nowId and toId[num-1] > nowId and words[num-1] != '(': #今のチャンクIdが最初のIdでなく, かかり先Idが最初のId出ない
                break
                
            num -=1
        
####    
    
        
##How##    
    if toId[num] == -1:
        while num > 0:
            How.insert(0, words[num])
            howId.append(chunkId[num])
            if (poss[num][0] =='名詞' and poss[num][1] != '非自立' and poss[num][1] != '接尾' and poss[num-1][6] != 'という'):
                break
            num -= 1
        
####


##What## 
        
    for c in nani:
        if poss[num][0] == '助詞' and words[num] == c and toId[num] in howId: #続く助詞がWhatの後に続くものの場合1
            while num > 0:
                num -= 1
                What.insert(0, words[num])
                if (poss[num][0] =='名詞' and poss[num][1] != '非自立' and poss[num][1] != '接尾') or (poss[num][1] == '自立'  and poss[num][6] != 'する' and poss[num][6] != 'なる'):
                    break


#            num += 1
            
####    
    else:
        num -= 1

print('Who:%s' %(Who))
print('Where:%s' %(Where))
print('When:%s' %(When))
print('What:%s' %(What))
print('How:%s' %("".join(How)))

実行例

実行例3にて「我々」はWho要素として抽出できましたが、「キングコング」が別の要素として抽出されてしまいました。
その他の要素は概ね正しく抽出できています。

実行例1: 入力: きょうの会見に合わせたかのように宮迫さんがユーチューバーとしてまーデビューされました 出力: Who:['宮迫'] Where: When:['きょうの'] What:['宮迫', 'さん'] How:ユーチューバーとしてまーデビューされました

実行例2: 入力: 下高速道路は東名高速の下りできょう午前8時頃秦野中井インターチェンジ付近で最大30キロの渋滞が予想されるなどしています 出力: Who: Where:['下', '道路', '東名', '秦野', '中井', 'インター', '付近'] When:['きょう', '午前', '8時頃'] What:['高速道路', '渋滞'] How:予想されるなどしています

実行例3: 入力:まあ我々キングコングがスピード出世みたいなことになったんですけども 出力: Who:['我々'] Where: When: What:['キングコング'] How:出世みたいなことになったんですけども

次回の予定

次回はHow要素とWhat要素の抽出を改善したいと思います。
また、今後は大きく手法を変えることはせず、様々な例を試して問題を洗い出したいと思います。


次の記事へ

前の記事へ 戻る