ユーザ用ツール

サイト用ツール


korean:mecab:python_mk_tfidf

HanDicの出力結果をPythonで利用する:TF-IDFの計算

はじめに

HanDicを使ったMeCabの出力結果をPythonで利用する例として,文書中に現れる単語の重要度を示す,TF-IDFの計算を行ってみます.今回は中期朝鮮語の資料である『석보상절(釈譜詳節)』(1447年刊)を,中期朝鮮語のMeCab用解析辞書「MkHanDic」で解析した結果を使います.解析結果については,MeCabの出力そのままではなく,テキストファイルに出力した結果を手作業で修正したものを利用します.辞書構築の際の学習用データとして用いているものです.

上記資料の原刊本のうち,巻6,9,13,19,23,24の本文のみ解析して修正した巻次ごとのテキストファイルが,スクリプトと同じディレクトリ下のsekbo_textsというディレクトリにあるものとします.巻6のファイル(ファイル名はc_sekbo_06_main_v03.txtとする)の冒頭は以下の通りとなっています:

世尊	Noun,固有名詞,人名,*,*,世尊,世尊,世尊,*,NNP
'i	Ending,助詞,主格,*,*,이,이,*,*,JKS
象頭山	Noun,固有名詞,地名,*,*,象頭山,象頭山,象頭山,*,NNP
'ai	Ending,助詞,処格,*,*,애,애,*,*,JKB
ga	Verb,自立,*,語基2,*,가다01,가,*,*,VV
sia	Prefinal,尊敬,*,語基3,*,시,샤,*,*,EP
龍	Noun,普通,*,*,*,龍,龍,龍,*,NNG
goa	Ending,助詞,接続助詞,*,*,과,과,*,*,JC
鬼神	Noun,普通,*,*,*,鬼神,鬼神,鬼神,*,NNG
goa	Ending,助詞,接続助詞,*,*,과,과,*,*,JC
'uih@'ia	Verb,自立,*,語基3,*,위다,위야,*,*,VV
說法	Noun,普通,動作,*,*,說法,說法,說法,*,NNG
h@	Suffix,動詞派生,*,語基1,*,다80,,*,*,XSV
de	Prefinal,回想,*,語基2,*,더,더,*,*,EP
si	Prefinal,尊敬,*,語基1,*,시,시,*,*,EP
da	Ending,語尾,終止形,*,1接続,다,다,*,*,EF
.	Symbol,ピリオド,*,*,*,.,.,*,*,SF
EOS

中期朝鮮語に固有の文字は,表示されていないかと思います.表層形(各行の冒頭)にアルファベット転写を用いていますが,この表記についてはmecab-k2alphaのアルファベット転写表を参照してください.

やること

上述の『釈譜詳節』のそれぞれの巻次について,名詞類(普通名詞,固有名詞,語根)のTF-IDFを計算します.その上で,各巻次のTF-IDF上位10語を列挙します.基本的にはHanDicをPythonで利用する:TF-IDFの計算のやり方と同じです.

準備

今回はMeCabを呼び出したりしないので,必要最低限のモジュールだけ呼び出します.

import glob, os
from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd

読み込んだファイルの処理

読み込んだファイルについて処理する関数を定義します.出力結果は各行「表層形[タブ文字]コンマ区切りの素性」という形式なので,まずsplit('\t')で表層形と素性とを区切った後,素性に当たる部分をsplit(',')で個別の素性に分け,配列に入れます.

素性のうち「世宗タグ」がNNG(普通名詞),NNP(固有名詞),XR(語根)に該当するものを抽出し,スペース区切りの配列にします.

def extract(file):
    words = []
    with open(file, mode='rt', encoding='utf-8') as fi:
        for line in fi:
            mecab_features = []
            line = line.rstrip('\n')
            if line == 'EOS':
                continue
            mecab_features = line.split('\t')[1].split(',')
            if mecab_features[9] in ['NNG', 'NNP', 'XR']:
                words.append(mecab_features[5])
    text_result = ' '.join(words)
    return text_result

こちらもHanDicをPythonで利用する:TF-IDFの計算と同じく,普通名詞と固有名詞,語根に限定しました.

ファイルの読み込みとその処理

ディレクトリsekbo_texts内にあるファイルをそれぞれ読み込み,前節の処理を行います.

# sekbo_texts フォルダ内のテキスト読み込み
all_files = glob.glob("sekbo_texts/*.txt")
docs = []
titles = []
for i in all_files:
	text = extract(i)
	titles.append(os.path.split(i)[1])
	docs.append(text)

それぞれのファイル名を取り出して,別途配列に入れます.

TF-IDFの計算と上位10語の表示

ここから後は,HanDicをPythonで利用する:TF-IDFの計算と同じ手順です.scikit-learnでTF-IDFを計算します.

[2021/11\09 追記] TfidfVectorizer()token_patternを書いておかないと,古ハングルが無視されて計算されてしまいます.Unicodeの私用領域(PUA)に含まれる古ハングルを,文字コードで指定することにしました(参照:古ハングル(Wikipedia)).これで合っているか分かりませんが,ともかく古ハングルが含まれた項目も計算に入るようになります.

# モデルを作成
vectorizer = TfidfVectorizer(smooth_idf=False, token_pattern='(?u)[\\w\\ue0bc-\\uefff\\uf100-\\uf66e\\uf784-\\uf800\\uf806-\\uf864\\uf86a-\\uf8f7]+')
values = vectorizer.fit_transform(docs).toarray()
feature_names = vectorizer.get_feature_names_out()
df = pd.DataFrame(values, columns = feature_names, index=titles)

今回はファイル数が少ないので,全てのファイルについてTF-IDFで上位の10語を表示するようにしました.

for num in range(len(df)):
    temp_df = []
    temp_df = df[num:num+1].T
    temp_df = temp_df.sort_values(by=titles[num], ascending=False)
    print(temp_df.head(10))

結果は以下の通り([2021/11/09 追記] token_patternを変えたことで,計算結果に違いが出ましたので変更しておきます.傾向にあまり変わりはありません):

     c_sekbo_06_main_v03.txt
須達                  0.688172
舍利弗                 0.260852
精舍                  0.233487
부텨                  0.233296
耶輸                  0.159754
太子                  0.149058
六師                  0.147465
사                  0.145260
目連                  0.122888
舍衛國                 0.120090
         c_sekbo_09_main_v03.txt
有情                      0.475275
藥師瑠璃光如來                 0.398618
橫死                      0.245303
大願                      0.199309
일훔                      0.197701
來世                      0.183978
菩提                      0.183978
惡趣                      0.137983
病                       0.123366
文殊師利                    0.120877
     c_sekbo_13_main_v03.txt
부텨                  0.454087
舍利弗                 0.321053
佛道                  0.236824
菩薩                  0.224191
諸佛                  0.219559
法                   0.189619
사                  0.179639
衆生                  0.149699
일훔                  0.129739
佛乘                  0.111446
     c_sekbo_19_main_v03.txt
소리                  0.354649
사                  0.231608
香                   0.213933
부텨                  0.209894
經                   0.172931
菩薩                  0.171147
隨喜                  0.161648
法華經                 0.161648
得大勢                 0.161648
得                   0.159230
     c_sekbo_23_main_v03.txt
부텨                  0.322129
舍利                  0.289234
棺                   0.231640
供養                  0.219634
拘尸城                 0.204388
金棺                  0.204388
大衆                  0.178889
如來                  0.165945
사                  0.165945
一切                  0.161065
     c_sekbo_24_main_v03.txt
王                   0.605065
尊者                  0.305280
阿育王                 0.280858
부텨                  0.209953
사                  0.139969
夫人                  0.137691
善容                  0.134323
놈                   0.134323
太子                  0.133305
塔                   0.129287

須達と舎利仏のストーリーが中心的な巻6,『薬師瑠璃光如来本願功徳経』の翻訳である巻9,『法華経』の翻訳である巻13,19,釈迦入滅後,舎利の扱いを論じる巻23,阿育王の話が出てくる巻24と,それぞれの特徴が示されています.

終わりに

取得したデータをMeCabで処理しながら,その結果を利用するということが多いかと思いますが,既に出力結果がある場合,また出力結果を修正した正解ファイルがある場合も,簡単に処理することができます.形態素解析の結果には誤りも含まれることがあるため,正解ファイルを利用する,ということもニーズがあると思われます.

korean/mecab/python_mk_tfidf.txt · 最終更新: 2021/11/12 19:38 by yoshi