Tokenizer API
TokenizerBuilder
TokenizerBuilder はビルダーパターンを使用して Tokenizer インスタンスを設定・構築します。
コンストラクタ
TokenizerBuilder()
デフォルト設定で新しいビルダーを作成します。
from lindera import TokenizerBuilder
builder = TokenizerBuilder()
TokenizerBuilder().from_file(file_path)
YAML ファイルから設定を読み込み、新しいビルダーを返します。segmenter、
character_filters、token_filters を含む完全な例は
lindera-python/resources/lindera.yml
を参照してください。
builder = TokenizerBuilder().from_file("lindera.yml")
設定メソッド
すべてのセッターメソッドはメソッドチェーンのために self を返します。
set_mode(mode, penalty=None)
トークナイズモードを設定します。
"normal"-- 標準的なトークナイズ(デフォルト)"decompose"-- 複合語をより小さな単位に分解
penalty は "decompose" モードが使う Penalty です。None(デフォルト)では既定のペナルティを使います。"normal" とペナルティを一緒に渡すと ValueError が、Penalty でない値を渡すと TypeError が送出されます。
builder.set_mode("normal")
builder.set_mode("decompose", Penalty(kanji_penalty_length_penalty=0))
set_dictionary(path)
システム辞書のパスまたは URI を設定します。
# 埋め込み辞書を使用
builder.set_dictionary("embedded://ipadic")
# 外部辞書を使用
builder.set_dictionary("/path/to/dictionary")
set_user_dictionary(uri)
ユーザー辞書の URI を設定します。
builder.set_user_dictionary("/path/to/user_dictionary.csv")
set_keep_whitespace(keep)
出力に空白トークンを含めるかどうかを制御します。残した空白はラティスにも残るため、他のトークンも、MeCab と同様に空白をラティス上で読み飛ばすデフォルトの出力と変わることがあります。空白を出力せずにラティスにだけ残すには、代わりに set_skip_whitespace(False) を使います。
builder.set_keep_whitespace(True)
set_skip_whitespace(skip)
空白をラティス上で読み飛ばすかどうかを設定します。skip の意味は設定ファイルの segmenter.skip_whitespace と同じです:
True-- 空白を読み飛ばし、MeCab と同様に空白の前後の語を直接接続します。False-- 空白を独立したノード(空白の見出し語かSPACEの未知語)としてラティスに残します(v7 より前の動作)。空白は引き続き出力から除外されます。None-- 辞書のmetadata.jsonのデフォルトです。SudachiDict 以外では読み飛ばします。以前の呼び出しを取り消すときに使います。
ここで設定した値は、辞書のデフォルトと、from_file で読み込んだ skip_whitespace より優先されます。空白トークンを残すとき(set_keep_whitespace(True))は効果がありません。残した空白は常にラティスに残るためです。それ以外の値では TypeError が送出されます。
たとえば IPADIC では、Google が 新しい の が は、デフォルトでは助詞(助詞)、set_skip_whitespace(False) では接続詞(接続詞)と解析されます。詳しくは Segmenter を参照してください。
# v7 より前と同じく、空白をラティスに残す
builder.set_skip_whitespace(False)
set_space_penalty(value)
韓国語向けの左側空白ペナルティ(left-space penalty)を設定します。直前に空白がある候補のうち、本来は前の語に空白なしで付く品詞(助詞、語尾など)の候補にコストを加算します。value の意味は設定ファイルの segmenter.space_penalty と同じです:
None-- デフォルト。辞書がmetadata.jsonに同梱するルールがあればそれを使います(ko-dic は mecab-ko-dic のルールを同梱し、他の同梱辞書はルールを持ちません)。以前の呼び出しを取り消すときにも使います。False-- ペナルティをオフにします。True-- 辞書のルールを要求します。ルールを同梱しない辞書ではbuild()がValueErrorを送出します。{"rules": [{"pos": [...], "cost": n}, ...]}形式のdict-- 辞書のルールの代わりにこのルールを適用します。先頭品詞タグがposに含まれる候補にcostを加算し、最初に一致したルールが使われます。
それ以外の値では ValueError が送出されます(任意のオブジェクトなど JSON に対応しない値は、append_token_filter と同様に TypeError になります)。
# ペナルティをオフにする
builder.set_space_penalty(False)
# 明示的なルール
builder.set_space_penalty({
"rules": [
{"pos": ["EC", "EF", "EP", "ETM", "ETN", "VCP", "XSA", "XSN", "XSV"], "cost": 3000},
{"pos": ["JC", "JKB", "JKC", "JKG", "JKO", "JKQ", "JKS", "JKV", "JX"], "cost": 6000},
]
})
[!NOTE] v6.1.0 から、ko-dic では mecab-ko と同じく左側空白ペナルティがデフォルトで適用されます。たとえば
검색 이 잘 된다の이は感動詞ICと解析されます(ペナルティがなければ主格助詞JKS)。オフにするにはbuilder.set_space_penalty(False)を呼び出してください。ルールを同梱しているのは Lindera 6.1.0 以降でビルドした ko-dic だけです。v6.0.0 リリースの ko-dic ではペナルティはオフのままで、辞書を再ビルドするまでTrueはエラーになります。詳しくは Segmenter を参照してください。
append_character_filter(kind, args=None)
前処理パイプラインに文字フィルタを追加します。
builder.append_character_filter("unicode_normalize", {"kind": "nfkc"})
append_token_filter(kind, args=None)
後処理パイプラインにトークンフィルタを追加します。
builder.append_token_filter("lowercase", {})
set_space_penalty、append_character_filter、append_token_filter の引数は、list と dict の入れ子が 128 段までです。それより深い値や、自分自身を含む値を渡すと ValueError が送出されます。
ビルド
build()
設定された内容で Tokenizer をビルドして返します。
tokenizer = builder.build()
Tokenizer
Tokenizer はテキストに対して形態素解析を行います。
Tokenizer の作成
Tokenizer(dictionary, mode="normal", user_dictionary=None, space_penalty=None, penalty=None)
読み込み済みの辞書から直接トークナイザーを作成します。
space_penalty には TokenizerBuilder.set_space_penalty と同じ値を渡せます。None(デフォルト)では辞書が同梱する左側空白ペナルティのルールを使うため、ko-dic ではペナルティがオンになります。オフにするには False を渡します。不正な設定では、set_space_penalty や build() と同じエラーが送出されます。
penalty には、TokenizerBuilder.set_mode と同じく "decompose" モードの Penalty を渡せます。エラーも set_mode と同じです。
from lindera import Tokenizer, load_dictionary
dictionary = load_dictionary("embedded://ipadic")
tokenizer = Tokenizer(dictionary, mode="normal")
# 左側空白ペナルティなしの ko-dic
ko_tokenizer = Tokenizer(load_dictionary("embedded://ko-dic"), space_penalty=False)
Tokenizer メソッド
tokenize(text)
入力テキストをトークナイズし、Token オブジェクトのリストを返します。
tokens = tokenizer.tokenize("形態素解析")
パラメータ:
| 名前 | 型 | 説明 |
|---|---|---|
text | str | トークナイズするテキスト |
戻り値: list[Token]
tokenize_surfaces(text)
入力テキストをトークナイズし、トークンの surface のみを文字列のリストとして返します。分かち書き用途の高速パスです。Token オブジェクトを生成せず、形態素の詳細情報もロードしないため、surface 文字列だけが必要な場合は tokenize より大幅に高速です。結果は [t.surface for t in tokenizer.tokenize(text)] と一致します。
surfaces = tokenizer.tokenize_surfaces("形態素解析")
# ["形態素", "解析"]
パラメータ:
| 名前 | 型 | 説明 |
|---|---|---|
text | str | トークナイズするテキスト |
戻り値: list[str]
tokenize_nbest(text, n, unique=False, cost_threshold=None)
N-best トークナイズ結果を返します。各結果はトータルパスコストとペアになっています。
results = tokenizer.tokenize_nbest("すもももももももものうち", n=3)
for tokens, cost in results:
print(cost, [t.surface for t in tokens])
パラメータ:
| 名前 | 型 | 説明 |
|---|---|---|
text | str | トークナイズするテキスト |
n | int | 返す結果の数 |
unique | bool | 結果の重複を排除(デフォルト: False) |
cost_threshold | int または None | 最良パスからの最大コスト差(デフォルト: None) |
戻り値: list[tuple[list[Token], int]]
Mode
Mode はトークナイズモードを表します。モードの確認や比較のためのスタンドアロンな
ヘルパーとして提供されています。TokenizerBuilder.set_mode() と Tokenizer の
コンストラクタは、Mode インスタンスではなく単純なモード文字列
("normal" または "decompose")を受け取ります。decompose モードのペナルティは、
それぞれの penalty 引数で渡します(下記 Penalty を参照)。
Mode の作成
Mode(mode_str=None)
Mode を作成します。"normal" / "Normal"(省略時のデフォルト)または
"decompose" / "Decompose" を受け付けます。それ以外の値を指定すると
ValueError が発生します。
from lindera import Mode
mode = Mode("normal")
mode = Mode("decompose")
mode = Mode() # デフォルトは "normal"
メソッド
| メソッド | 戻り値 | 説明 |
|---|---|---|
__str__() | str | "normal" または "decompose" |
__repr__() | str | 例: "Mode.Normal" |
is_normal() | bool | モードが "normal" の場合 True |
is_decompose() | bool | モードが "decompose" の場合 True |
mode = Mode("decompose")
str(mode) # "decompose"
repr(mode) # "Mode.Decompose"
mode.is_normal() # False
mode.is_decompose() # True
Penalty
Penalty は "decompose" モードのセグメンテーションで使用される、長さに基づく
ペナルティの閾値を設定します。
Penalty の作成
Penalty(kanji_penalty_length_threshold=2, kanji_penalty_length_penalty=3000, other_penalty_length_threshold=7, other_penalty_length_penalty=1700)
すべての引数は省略可能で、上記の値がデフォルトとして使用されます。
from lindera import Penalty
penalty = Penalty(
kanji_penalty_length_threshold=2,
kanji_penalty_length_penalty=3000,
other_penalty_length_threshold=7,
other_penalty_length_penalty=1700,
)
Penalty のプロパティ
4 つのフィールドはすべて取得・設定の両方をサポートしています:
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
kanji_penalty_length_threshold | int | 2 | ペナルティが適用される、漢字のみの表層形の長さの閾値 |
kanji_penalty_length_penalty | int | 3000 | 閾値を超える漢字のみの表層形に加算されるコストペナルティ |
other_penalty_length_threshold | int | 7 | 漢字のみでない表層形にペナルティが適用される長さの閾値 |
other_penalty_length_penalty | int | 1700 | 閾値を超える漢字のみでない表層形に加算されるコストペナルティ |
penalty.kanji_penalty_length_threshold = 3
print(penalty.kanji_penalty_length_threshold) # 3
Penalty の使い方
Penalty は "decompose" と一緒に TokenizerBuilder.set_mode() か Tokenizer のコンストラクタ に渡します。長さのペナルティをなくすと、decompose モードでも長い語が分割されずに残ります。
from lindera import Penalty, Tokenizer, TokenizerBuilder, load_dictionary
text = "関西国際空港限定トートバッグ"
penalty = Penalty(kanji_penalty_length_penalty=0, other_penalty_length_penalty=0)
builder = TokenizerBuilder().set_dictionary("embedded://ipadic")
tokenizer = builder.set_mode("decompose").build()
print([token.surface for token in tokenizer.tokenize(text)])
# ['関西', '国際', '空港', '限定', 'トートバッグ']
tokenizer = builder.set_mode("decompose", penalty).build()
print([token.surface for token in tokenizer.tokenize(text)])
# ['関西国際空港', '限定', 'トートバッグ']
tokenizer = Tokenizer(load_dictionary("embedded://ipadic"), mode="decompose", penalty=penalty)
print([token.surface for token in tokenizer.tokenize(text)])
# ['関西国際空港', '限定', 'トートバッグ']
"normal" モードと一緒に Penalty を渡すと ValueError が送出されます。
Token
Token は単一の形態素トークンを表します。
プロパティ
| プロパティ | 型 | 説明 |
|---|---|---|
surface | str | トークンの表層形 |
byte_start | int | 元テキストでの開始バイト位置 |
byte_end | int | 元テキストでの終了バイト位置 |
position | int | トークンの位置インデックス |
word_id | int | 辞書の単語 ID |
is_unknown | bool | 辞書に登録されていない単語の場合 True |
details | list[str] または None | 形態素の詳細情報(品詞、読みなど) |
Token メソッド
get_detail(index)
指定されたインデックスの詳細文字列を返します。インデックスが範囲外の場合は None を返します。
token = tokenizer.tokenize("東京")[0]
pos = token.get_detail(0) # 例: "名詞"
subpos = token.get_detail(1) # 例: "固有名詞"
reading = token.get_detail(7) # 例: "トウキョウ"
パラメータ:
| 名前 | 型 | 説明 |
|---|---|---|
index | int | details リストへのゼロベースインデックス |
戻り値: str または None
to_dict()
トークンをプレーンな dict として返します。各フィールドは Python の自然な型を
保つため、独自のエンコーダなしでシリアライズできます。
import json
data = tokenizer.tokenize("東京")[0].to_dict()
# {'surface': '東京', 'byte_start': 0, 'byte_end': 6, 'position': 0,
# 'word_id': 12345, 'is_unknown': False, 'details': [...]}
json.dumps([token.to_dict() for token in tokens])
戻り値: surface、byte_start、byte_end、position、word_id、
is_unknown、details をキーに持つ dict。
details の構造は辞書によって異なります:
- IPADIC:
[品詞, 品詞細分類1, 品詞細分類2, 品詞細分類3, 活用型, 活用形, 原形, 読み, 発音] - UniDic: UniDic 仕様に準拠した詳細な形態素情報
- ko-dic / CC-CEDICT / Jieba: 各辞書固有の詳細フォーマット
エラーハンドリング
Lindera Python の関数は、カスタムの例外型ではなく標準的な Python の例外を送出します:
IOError(OSErrorのエイリアス) -- ファイルが存在しない、読み込めないなどの I/O 関連の失敗ValueError-- それ以外のすべてのケース(不正な設定、パースエラー、 トークナイズの失敗など)
from lindera import load_dictionary
try:
dictionary = load_dictionary("/path/that/does/not/exist")
except ValueError as e:
print(f"Failed to load dictionary: {e}")
lindera.LinderaError クラスも登録されていますが、このクレート内のどの関数からも
送出されることはありません -- 手動で構築・送出する場合にのみ使用できます。この
ライブラリのエラーを処理する際は、LinderaError ではなく IOError /
ValueError(または一般的な Exception)をキャッチしてください。