search
LoginSignup
9
Help us understand the problem. What are the problem?

posted at

updated at

Organization

SudachiPyを使ってみる

SudachiPyはワークス徳島人工知能NLP研究所が開発している形態素解析器SudachiのPython版です。
バージョン0.6.0からは実装をCythonからRustに変更し、以前のバージョンより20倍ほど実行速度が速くなっています。

導入

最初はPythonの仮想環境を作ります。

python -m venv supy-test

bashzshを使う場合は環境を有効にするために以下のようにします。

source supy-test/bin/activate

Windows上のPowershellの場合はPowershell版の有効化スクリプトを使います。

.\supy-test\Scripts\Activate.ps1
ARMのMac (Apple Silicon) の場合は追加のステップが必要です。

ARMのMacの場合はバイナリーのパッケージはまだ存在していないので、ビルドのためにRustのToolchainとPythonのパッケージも必要になります。
pip install setuptools_rust

インストール

準備が終わったら、SudachiPyをインストールします。

pip install sudachipy sudachidict_core

sudachidict_core の代わりに、sudachidict_small, sudachidict_fullもインストールできます。

試してみる

使い方は二通りあります。

まずは、コマンドラインツールsudachipyから起動確認をします。

$ echo "吾輩は猫である" | sudachipy
吾輩    代名詞,*,*,*,*,*        我が輩
は      助詞,係助詞,*,*,*,*     は
猫      名詞,普通名詞,一般,*,*,*        猫
で      助動詞,*,*,*,助動詞-ダ,連用形-一般      だ
ある    動詞,非自立可能,*,*,五段-ラ行,終止形-一般       有る
EOS

ライブラリとしての使い方

コマンドラインでの利用は簡単な試用にはいいですが、醍醐味があるのはライブラリとしての使い方です。

基本的な使い方は以下の3つのステップです:

>>> dict = sudachipy.Dictionary() # まずは辞書を作る
>>> tokenizer = dict.create() # 辞書から分割器を作る
>>> tokenizer.tokenize("吾輩は猫である") # 分割自体を行う
<MorphemeList[
  <Morpheme(吾輩, 0:2, (0, 350242))>,
  <Morpheme(, 2:3, (0, 122101))>,
  <Morpheme(, 3:4, (0, 571106))>,
  <Morpheme(, 4:5, (0, 101816))>,
  <Morpheme(ある, 5:7, (0, 12492))>,
]>

sudachipy.Dictionary(dict="full") では sudachidict_full を使えます。sudachidict_smallの場合はsudachipy.Dictionary(dict="small")を使ってください。

分かち書きの出力:

>>> morphemes = tokenizer.tokenize("吾輩は猫である")
>>> print(*[m.surface() for m in morphemes])
吾輩    ある

今後、SudachiPyは解析中にGILを使わないようにする予定です。スレッドごとに別のTokenizerのインスタンスを使うようにしてください。

コンポーネントの説明

Dictionaryは辞書データを持つ部品です。辞書データはimmutableなので、基本的に複数のDictionaryを作る必要がなく、スレッド間の共有もできます。

Tokenizerは解析中に可変な状態をもつコンポーネントです。中身は可変なので、スレッド間の共有は不可能です。

MorphemeListは解析の結果で、形態素列を表す型です。追加の状態を持つ必要がありPythonのListではなく独自実装ですが、Listと同じように使えます。

Morphemeは形態素です。様々な情報を持っています。大事なのは以下のものです。

  • begin() \ end():入力の文字列にたいして形態素の始まりと終わりの文字(正確に言えばUnicodeのCodepoint)のオフセット
  • surface():形態素の見出し、入力の文字列中の文字列
  • part_of_speech():UniDic体系の品詞
  • dictionary_form():活用可能な形態素の辞書形
  • normalized_form():正規化情報、例)あんまり→余り
  • reading_form():形態素の読み

分割の単位

Sudachiは複数の単位に分割できます。

  • C:固有表現レベル(既定値)
  • B:人間に自然なレベル
  • A:Unidicの短単位に相当するレベル

分割のレベルの指定の仕方は3通りあります。

すべての解析を1つのレベルで行う

この場合はTokenizerを作る際にDictionary.create()modeの引数として渡します。

>>> tokenizer = dict.create(mode=sudachipy.SplitMode.C) # 既定値はC
>>> tokenizer.tokenize("関西国際空港")
<MorphemeList[
  <Morpheme(関西国際空港, 0:6, (0, 1564531))>,
]>
>>> tokenizer = dict.create(mode=sudachipy.SplitMode.A)
>>> tokenizer.tokenize("関西国際空港")
<MorphemeList[
  <Morpheme(関西, 0:2, (0, 735344))>,
  <Morpheme(国際, 2:4, (0, 365535))>,
  <Morpheme(空港, 4:6, (0, 602797))>,
]>

この使い方は一番おすすめです。

解析ごとにレベルを変える

この場合はTokenizer.tokenize()modeの引数として渡します。

>>> tokenizer.tokenize("関西国際空港", mode=sudachipy.SplitMode.C)
<MorphemeList[
  <Morpheme(関西国際空港, 0:6, (0, 1564531))>,
]>
>>> tokenizer.tokenize("関西国際空港", mode=sudachipy.SplitMode.B)
<MorphemeList[
  <Morpheme(関西, 0:2, (0, 735344))>,
  <Morpheme(国際, 2:4, (0, 365535))>,
  <Morpheme(空港, 4:6, (0, 602797))>,
]>
>>> tokenizer.tokenize("関西国際空港", mode=sudachipy.SplitMode.A)
<MorphemeList[
  <Morpheme(関西, 0:2, (0, 735344))>,
  <Morpheme(国際, 2:4, (0, 365535))>,
  <Morpheme(空港, 4:6, (0, 602797))>,
]>

解析ごとに一時的にレベルが変更されるので、Tokenizerのデフォルトの分割モードは変更されません。

同時に複数のレベルを使いたい場合

この場合はMorpheme.split()を使います。

>>> tokenizer = dict.create(mode=sudachipy.SplitMode.C)
>>> morphemes = tokenizer.tokenize("関西国際空港")
>>> morphemes
<MorphemeList[
  <Morpheme(関西国際空港, 0:6, (0, 1564531))>,
]>
>>> morphemes[0].split(sudachipy.SplitMode.A)
<MorphemeList[
  <Morpheme(関西, 0:2, (0, 735344))>,
  <Morpheme(国際, 2:4, (0, 365535))>,
  <Morpheme(空港, 4:6, (0, 602797))>,
]>

良いSudachi Lifeを。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
9
Help us understand the problem. What are the problem?