MeCab

参考文献

  1. 日本テレビ東京で学ぶMeCabのコスト計算 | mwSoft (2024年03月19日参照).

Snippets

形態素解析する

「UniDic」国語研短単位自動解析用辞書|バックナンバーから辞書をダウンロードして配置し、形態素解析すると以下のようになる。
import MeCab
tagger = MeCab.Tagger('-d "C:/Program Files/MeCab/dic/unidic-csj-3.1.1-full"')
print(tagger.parse('ヒンメルはもういないじゃない'))
ヒンメル	名詞,普通名詞,一般,,,
は	助詞,係助詞,,,,,ハ,は,は,ワ,は,ワ,和,"","","","","","",係助,ハ,ハ,ハ,ハ,"","動詞%F2@0,名詞%F1,形容詞%F2@-1","",8059703733133824,29321
もう	副詞,,,,,,モウ,もう,もう,モー,もう,モー,和,"","","","","","",相,モウ,モウ,モウ,モウ,"0,1","","",10326896709607936,37569
い	動詞,非自立可能,,,上一段-ア行,未然形-一般,イル,居る,い,イ,いる,イル,和,"","","","","","",用,イ,イル,イ,イル,"0","C4","M4@1",710568013079105,2585
ない	助動詞,,,,助動詞-ナイ,終止形-一般,ナイ,ない,ない,ナイ,ない,ナイ,和,"","","","","","",助動,ナイ,ナイ,ナイ,ナイ,"","動詞%F3@0","",7542108634358443,27438
じゃ	助動詞,,,,助動詞-ダ,連用形-融合,ダ,だ,じゃ,ジャ,だ,ダ,和,"","","","","","",助動,ジャ,ダ,ジャ,ダ,"","名詞%F1","",6299110739157638,22916
ない	形容詞,非自立可能,,,形容詞,終止形-一般,ナイ,無い,ない,ナイ,ない,ナイ,和,"","","","","","",相,ナイ,ナイ,ナイ,ナイ,"1","C3","",7543208145986219,27442
EOS
ただこれだと結果の意味がわからないのでわかりやすくするとこうなる。
from IPython.display import display, HTML
import MeCab
import re
import pandas as pd

# ダブルクオートで囲まれていないカンマにマッチする正規表現
split_pattern = re.compile(r',(?=[^"]*(?:"[^"]*"[^"]*)*$)')

tagger = MeCab.Tagger('-d "C:/Program Files/MeCab/dic/unidic-csj-3.1.1-full"')
cols = [  # C:/Program Files/MeCab/dic/unidic-csj-3.1.1-full/dicrc をみると各トークンの特徴名リストがある
    'pos1', 'pos2', 'pos3', 'pos4', 'cType', 'cForm', 'lForm', 'lemma',
    'orth', 'pron', 'orthBase', 'pronBase', 'goshu', 'iType', 'iForm', 'fType', 'fForm',
    'iConType', 'fConType', 'type', 'kana', 'kanaBase',
    'form', 'formBase', 'aType', 'aConType', 'aModType', 'lid', 'lemma_id']
cols_ja = [  # https://clrd.ninjal.ac.jp/unidic/faq.html, https://hayashibe.jp/tr/mecab/dictionary/unidic/field
    '品詞大分類', '品詞中分類', '品詞小分類', '品詞細分類', '活用型', '活用形', '語彙素読み', '語彙素',
    '書字形出現形', '発音形出現形', '書字形基本形', '発音形基本形', '語種', '語頭変化化型', '語頭変化形',
    '語末変化化型', '語末変化形', '語頭変化結合型', '語末変化結合型', '語彙素類', '仮名形出現形', '仮名形基本形',
    '語形出現形', '語形基本形', 'アクセント型', 'アクセント結合型', 'アクセント修飾型', '語彙表ID', '語彙素ID']

# 形態素解析結果を格納するデータフレーム
df = pd.DataFrame(columns=pd.MultiIndex.from_tuples(
    [('surface', '表層形')] + [(col, col_ja) for col, col_ja in zip(cols, cols_ja)], names=['feature name', '特徴名']))

tokens = tagger.parse('ヒンメルはもういないじゃない').split('')
for i_token, token in enumerate(tokens):
    if token.strip() == 'EOS':
        break
    v = token.strip().split('\t')
    info = split_pattern.split(v[1])
    df.loc[i_token] = [v[0]] + info + [''] * (29 - len(info))

display(HTML(df.to_html()))
feature namesurfacepos1pos2pos3pos4cTypecFormlFormlemmaorthpronorthBasepronBasegoshuiTypeiFormfTypefFormiConTypefConTypetypekanakanaBaseformformBaseaTypeaConTypeaModTypelidlemma_id
特徴名表層形品詞大分類品詞中分類品詞小分類品詞細分類活用型活用形語彙素読み語彙素書字形出現形発音形出現形書字形基本形発音形基本形語種語頭変化化型語頭変化形語末変化化型語末変化形語頭変化結合型語末変化結合型語彙素類仮名形出現形仮名形基本形語形出現形語形基本形アクセント型アクセント結合型アクセント修飾型語彙表ID語彙素ID
0ヒンメル名詞普通名詞一般
1助詞係助詞""""""""""""係助"""動詞%F2@0,名詞%F1,形容詞%F2@-1"""805970373313382429321
2もう副詞モウもうもうモーもうモー""""""""""""モウモウモウモウ"0,1"""""1032689670960793637569
3動詞非自立可能上一段-ア行未然形-一般イル居るいるイル""""""""""""イルイル"0""C4""M4@1"7105680130791052585
4ない助動詞助動詞-ナイ終止形-一般ナイないないナイないナイ""""""""""""助動ナイナイナイナイ"""動詞%F3@0"""754210863435844327438
5じゃ助動詞助動詞-ダ連用形-融合じゃジャ""""""""""""助動ジャジャ"""名詞%F1"""629911073915763822916
6ない形容詞非自立可能形容詞終止形-一般ナイ無いないナイないナイ""""""""""""ナイナイナイナイ"1""C3"""754320814598621927442

ユーザ辞書を追加する

import MeCab
import subprocess
import os

dic_dir = 'C:/Program Files/MeCab/dic/unidic-csj-3.1.1-full'

# まずはユーザ辞書なしで形態素解析する
tagger = MeCab.Tagger(f'-d "{dic_dir}"')
node = tagger.parseToNode('葬送のフリーレン')
while node:
    print(node.surface)
    node = node.next

# ユーザ辞書を生成する
csv_name = 'hoge.csv'
dic_name = 'hoge.dic'
with open(csv_name, mode='w', encoding='utf8', newline='\n') as ofile:
    ofile.write('フリーレン,7166,4392,0,名詞,固有名詞,人名,一般,*,*\n')
ret = subprocess.run(
    ['C:/Program Files/MeCab/bin/mecab-dict-index.exe', '-d', dic_dir,
     '-u', dic_name, '-f', 'utf-8', '-t', 'utf-8', csv_name],
    capture_output=True, text=True)
print(ret.stdout)

# ユーザ辞書ありで形態素解析する
tagger = MeCab.Tagger(f'-d "{dic_dir}" -u "{os.getcwd()}/{dic_name}"')
node = tagger.parseToNode('葬送のフリーレン')
while node:
    print(node.surface)
    node = node.next

葬送
の
フリー
レン

reading hoge.csv ... 1
emitting double-array: 100% |###########################################| 

done!


葬送
の
フリーレン