6.2Kbの軽量日本語分かち書きライブラリ
Python版はこちら
wakachigaki
は辞書を使わない軽量の日本語分かち書き用ライブラリです。
ピュアなJavaScriptなのでNode.jsやDeno, ブラウザなど環境を問わず動作し、TypeScriptやES Module1にも対応しています。
予め分かち書きされた大量の日本語テキストから作成した機械学習モデルを内包することで辞書不要の分かち書きを実現しています。
学習にはWikipedia日本語版のダンプデータ全量を用いました。MeCab + mecab-ipadic-NEologd で得られる分かち書き結果を約90%の精度で再現することが出来ています。
単語境界の判定には文中に出現する文字の種類や並び順の情報のみを用いるようになっており、文字や単語単位で固有の情報を一切利用していないため未知語に非常に強いのが特徴です。
辞書を用いる kuromoji.js などと異なり品詞の推定機能はありませんが、その分インストールも実行も軽量で環境を問わず動作します。
npm install wakachigaki
import { tokenize } from 'wakachigaki'
/** CommonJSの場合 */
// const { tokenize } = require('wakachigaki')
tokenize('非常に効果的な機械学習モデル')
// => [ '非常', 'に', '効果', '的', 'な', '機械学習', 'モデル' ]
分かち書きされた結果を直接取得するだけでなく、テキスト内の各文字についてその文字の直後に単語境界がある確率を0~1の範囲の数値で取得することが出来ます。
import { features, predictProba } from 'wakachigaki'
// 特徴量を取得
const feats = features('非常に効果的な機械学習モデル')
predictProba(feats)
/*
=> [
0.0327992634970502, // 非
0.9901071412275622, // 常
0.9742190417471894, // に
0.04298367736033199, // 効
0.7249201317135311, // 果
0.9920294555733393, // 的
0.904908994982585, // な
0.10174356598870479, // 機
0.3827245071932094, // 械
0.11608892206899486, // 学
0.6410674063348171, // 習
0.0045548383234342614, // モ
0.00006214363582036111, // デ
0.9720230891240956 // ル
]
*/
tokenize()
関数は内部でこの数値が予め定義された閾値を超えているかどうかを判定の基準にしていて、閾値もまた threshold
という変数でexportされています。
import { features, predictProba, predict, threshold } from 'wakachigaki'
const feats = features('非常に効果的な機械学習モデル')
const probas = predictProba(feats)
// probas.map(p => p >= threshold) と同じ結果
predict(feats)
/*
=> [
false, // 非
true, // 常
true, // に
false, // 効
true, // 果
true, // 的
true, // な
false, // 機
false, // 械
false, // 学
true, // 習
false, // モ
false, // デ
true // ル
]
*/
内部で文字種の判定に利用している正規表現と判定用の関数も利用可能です。
正規表現の内容は src/feature/regexp.ts を参照して下さい。
import {
regexp,
isHiragana,
isKatakana,
isKanji,
isNumeralKanji,
isAlphabet,
isNumeral,
} from 'wakachigaki'
/**
* 与えられた文字列が文字種判定用の正規表現を満たすかどうかチェックする関数。入力は複数文字でもOK
* 以下は全てtrueになる例
**/
// ひらがな
isHiragana('あ')
// カタカナ
isKatakana('カ')
// 漢字
isKanji('漢字')
// 漢数字
isNumeralKanji('一二三四五六七八九十百千万億兆')
// アルファベット (半角, 全角を無視)
isAlphabet('aa')
// 数字 (半角, 全角を無視)
isNumeral('99')
wakachigaki
自体では特にブラウザ用にビルドしたコードを配布していませんが、元々他パッケージへの依存がなくES Module形式に対応しているため unpkg.com などのCDNを経由すればすぐに動作させることが出来ます。
下記のコードをhtmlに貼り付ければ多くのブラウザでそのまま動くはずです。
<script type="module">
import { tokenize } from 'https://unpkg.com/[email protected]'
console.log(tokenize('ブラウザで分かち書きのテスト'))
// => [ 'ブラウザ', 'で', '分かち', '書き', 'の', 'テスト']
</script>
wakachigaki
はNode.js固有のAPIを使用していないためDeno環境でも動作します。
ブラウザ同様にCDNとしてunpkgを利用することも出来ますが、TypeScriptの型定義の配布に対応した Skypack を利用するのがおすすめです。
import { tokenize } from 'https://cdn.skypack.dev/[email protected]?dts'
console.log(tokenize('Denoで分かち書きのテスト'))
// => ['Deno', 'で', '分かち', '書き', 'の', 'テスト']
下記の表はJS環境で利用可能な類似のライブラリと併せて精度の比較を行ったものです。
比較用のコーパスにはNHN Japan株式会社提供のlivedoor ニュースコーパスを利用しました。
各記事を行単位に分解し適宜URLのみのものを取り除くなど前処理をして得られた約10万の文章について、MeCab + mecab-ipadic-NEologdで行った分かち書き結果を正解として各数値を算出しました。
従来の手法と比べても遜色ない結果が得られていることがわかります。
ただしwakachigaki
がそもそも学習にmecab-ipadic-NEologd
を用いているために新語や複合語に強くなっており、同列の条件での比較にはなっていない点に注意して下さい。あくまで参考程度の結果です。
特に高く見える適合率については、他ライブラリと比べて判定した単語境界の数
が少なく実際の単語境界の数
に近い数字になっていることからもmecab-ipadic-NEologd
から学習した複合語の判定傾向の影響が強く出ていると考えられます。
ライブラリ | 単語境界の数 | 判定数 | 正答数 | 一致率 | 適合率 | 再現率 | F2スコア |
---|---|---|---|---|---|---|---|
wakachigaki | 4611683 | 4589286 | 4234587 | 0.919 | 0.923 | 0.918 | 0.920 |
TinySegmenter | 4611683 | 5055596 | 4170853 | 0.824 | 0.825 | 0.904 | 0.863 |
kuromoji.js (デフォルト辞書) | 4611683 | 5015672 | 4312946 | 0.872 | 0.860 | 0.935 | 0.896 |
項目の意味
項目名 | 説明 |
---|---|
単語境界の数 | コーパス全体に対してMeCabが出力した単語境界の総数 |
判定数 | ライブラリが出力した単語境界の総数 |
正答数 | ライブラリが出力した単語境界のうち正解だったものの数 |
一致率 | 非単語境界と判定したものも含む全体の一致率 (Accuracy) |
適合率 | 正答数 ÷ 判定数 (Precision) |
再現率 | 正答数 ÷ 単語境界の数 (Recall) |
F2スコア | 適合率と再現率の調和平均 |
JSでアプリケーションを開発していると検索やレコメンド機能の実装などで日本語の分かち書きを行いたい時があります。
そんな時に npm install
したらサクっと使えてブラウザやDenoでも動いてESM, TypeScriptにも対応しているものがあれば嬉しいと思ったのが直接の動機です。
特に最近はサーバとブラウザどちらでも動く処理を書く機会が多かったりサーバレス系のインフラの出番が増えて取り回しの良い軽量なライブラリが求められます。
そこで wakachigaki
は 動作に環境依存がないこと、バンドルサイズがごく軽量なこと、ES Module, TypeScriptに対応していることを目指して開発されました。
機械学習モデルを利用した分かち書きの学習方法を検討している際 TinySegmenter がほぼ同様の構成になっているのを発見し大いに参考にさせて頂きました。
データの加工と学習にはPythonを使い、Wikipedia日本語版のダンプデータを全量使ってモデルの学習を行っています。
教師データの分かち書きには MeCab + mecab-ipadic-NEologd を利用しました。
コーパス内の各文字に対して複数のパラメータでNgramを取得し、漢字、ひらがな、カタカナなど文字の種類と文字のハッシュ値から算出した文字グループを特徴量として抽出、その文字の直後が単語境界かどうかの二値分類を学習しています。
Tiny Segmenterでも解説されていますが、クライアントに配布することも考えると学習結果として取り出すモデルのパラメータは出来る限り軽量にしたかったのでモデルはL1ノルム正則化ロジスティック回帰を採用し、確率的勾配降下法によるミニバッチ学習を行いました。
結果、モデルを表現するパラメータのJSONファイルはgzip後でわずか3Kbという軽量サイズになっています。
(学習用のコードもGitHubで公開する予定です)
機械学習モデルの構築にあたり非常に優秀な機械学習エンジニアの友人たちに多大な助力を頂きました。感謝します🙌
Footnotes
-
ブラウザ用にES Module形式のコードを配布していますが、パッケージ自体が厳密にNode.jsのNative ESMに対応しているわけではありません。Node.jsでは従来通りCommonJS形式のパッケージとして読み込まれます。TypeScriptが正式にNative ESMに対応した段階でDual Package化する予定です。 ↩