Python で形態素解析 の速度比較
- シンプルに分かち書きだけを期待して
- pip でサクッとインストール終わるヤツ
- 環境
docker pull python:3-slim
比較対象
- janome
- sudachi
- ginza
- mecab
- fugashi
- tinysegmenter
準備
pip install janome
pip install sudachipy
pip install ginza sudachidict_core
pip install mecab-python3
pip install fugashi[unidic-lite]
pip install tinysegmenter
参考:pip freeze
blis==0.4.1
catalogue==1.0.0
certifi==2020.4.5.2
chardet==3.0.4
cymem==2.0.3
Cython==0.29.19
dartsclone==0.9.0
fugashi==0.2.3
ginza==3.1.2
idna==2.9
ja-ginza==3.1.0
ja-ginza-dict==3.1.0
Janome==0.3.10
mecab-python3==0.996.5
murmurhash==1.0.2
numpy==1.18.5
plac==1.1.3
preshed==3.0.2
requests==2.23.0
sortedcontainers==2.1.0
spacy==2.2.4
srsly==1.0.2
SudachiDict-core==20200330
SudachiPy==0.4.5
thinc==7.4.0
tinysegmenter==0.4
tqdm==4.46.1
unidic-lite==1.0.6
urllib3==1.25.9
wasabi==0.6.0
コードと実行結果
コードを見る
import time
from janome.tokenizer import Tokenizer
from sudachipy import dictionary
import spacy
from MeCab import Tagger as mecab
from fugashi import Tagger as fugashi
import tinysegmenter
def use_janome(s, cache=None):
t = Tokenizer() if cache is None else cache
[token.surface for token in t.tokenize(s)]
return t
def use_sudachi(s, cache=None):
t = dictionary.Dictionary().create() if cache is None else cache
[token.surface() for token in t.tokenize(s)]
return t
def use_ginza(s, cache=None):
t = spacy.load('ja_ginza') if cache is None else cache
[token for token in t(s)]
return t
def use_mecab(s, cache=None):
t = mecab('-Owakati')
[token for token in t.parse(s).split(' ')]
return t
def use_fugashi(s, cache=None):
t = fugashi('-Owakati')
t(s)
return t
def use_tinysegmenter(s, cache=None):
t = tinysegmenter.TinySegmenter()
t.tokenize(s)
return t
def stopwatch(func, times=100):
# 桃太郎 芥川龍之介 https://www.aozora.gr.jp/cards/000879/card100.html
s = 'むかし、むかし、大むかし、ある深い山の奥に大きい桃《もも》の木が一本あった。大きいとだけではいい足りないかも知れない。この桃の枝は雲の上にひろがり、この桃の根は大地《だいち》の底の黄泉《よみ》の国にさえ及んでいた。何でも天地|開闢《かいびゃく》の頃《ころ》おい、伊弉諾《いざなぎ》の尊《みこと》は黄最津平阪《よもつひらさか》に八《やっ》つの雷《いかずち》を却《しりぞ》けるため、桃の実《み》を礫《つぶて》に打ったという、――その神代《かみよ》の桃の実はこの木の枝になっていたのである。'
time_s = time.perf_counter()
cache = None
for i in range(times):
cache = func(s, cache)
time_e = time.perf_counter()
return time_e - time_s
def main():
d = {
'janome': stopwatch(use_janome),
'sudachi': stopwatch(use_sudachi),
'ginza': stopwatch(use_ginza),
'mecab': stopwatch(use_mecab),
'fugashi': stopwatch(use_fugashi),
'tinysegmenter': stopwatch(use_tinysegmenter)
}
d = sorted(d.items(), key=lambda x:x[1])
print('\n'.join(map(str, d)))
if __name__ == '__main__':
main()
('mecab', 0.09558620000007068)
('fugashi', 0.1353556000003664)
('tinysegmenter', 0.655696199999511)
('janome', 3.070499899999959)
('sudachi', 5.18910169999981)
('ginza', 9.577376000000186)
感想
- そら MeCab は Python実装でなくネイティブなんで 圧倒的 、知ってた
- 便利とか精度とかに応じて重くなるだろうと思ってた
- tinysegmenter は目的が分かち書き特化なので Python実装だけど早い
- janome の速さは期待通り、sudachi, ginza と差があるもんなんですね
- 初めて速度比較した
- はじめ tokenizer 初期化をループ中にいれちゃってひどかった
- nagisa, UniDic2UD はインストールしんどいので今回不採用
- (コメントありがとうございます) Windows を主戦場にしてたら MeCab ってインストールが面倒だと思い込んでた
以上