fastTextとjanomeで問い合わせのカテゴリ分けを自動化する(Windows向け)
とあるパッケージの保守を10年ほどしていて、問い合わせを全てRedmine のチケットで管理していた。
カスタムフィールドにどの機能の話なのかカテゴリを用意して、チケット作成時に保守担当者に選択してもらっていた。ただ、後から分析しようと思ってカテゴリを見てみると、結構担当者によってまちまちというか、間違っていることも多かった。
これまでは分析のときにそれぞれ直していたが、どうにかチケット作成時に正しいカテゴリを選択してもらえないかと思い、fastText で自動化することにした。
fastText の導入環境
fastText とは、Facebook が作成した自然言語処理のライブラリだ。高速かつ簡単に利用できる。
今回は、これまでRedmine に蓄積した約2000の問い合わせを教師データに、問い合わせの内容から対象カテゴリを分類するようにした。
環境、ライブラリは以下の通り。
- Windows10
- PyCharm
- fastText
- janome
日本語をfastTextで処理する場合は、事前に分かち書きという処理をする必要がある。分かち書きにはMeCab というライブラリを使う情報が多いが、この自動化をした当時はpip install で
ERROR: Command errored out with exit status 1:
のエラーが出て解消するのが面倒だったので、簡単に入れられるjanome を採用した。
(※現在はmecab もpip install で簡単に入れられる様子)
事前準備
まずはfastText とjanome を導入する。
PyCharm でプロジェクトを作成し、View - Tool Windows - Terminal で以下を実行。
git clone https://github.com/facebookresearch/fastText.git cd fastText pip install . pip install janome
モデルの作成
まずはRedmine からチケットをCSV エクスポートする。そしてカテゴリと問い合わせの題名+本文だけに加工する。こんなイメージだ。
issues.csv
機能A,題名+本文 機能B,題名+本文 機能D,題名+本文 機能E,題名+本文 機能C,題名+本文
これを読み込みモデルを作成する。
ModelCreator.py
import csv from janome.tokenizer import Tokenizer import fasttext as ft with open(r'PATH-TO-CSV\issues.csv') as c: reader = csv.reader(c) tokenizer = Tokenizer() with open(r'PATH-TO-MODEL\model.txt', 'a', encoding='UTF-8') as f: for row in reader: token = tokenizer.tokenize(row[1].replace('\n', ''), wakati=True) f.write('__label__' + row[0] + ' , ' + " ".join(token) + '\n') model = ft.train_supervised(r'PATH-TO-MODEL\model.txt', epoch=5, loss="hs") model.save_model(r'PATH-TO-MODEL\fasttext.bin')
ポイントは
f.write('__label__' + row[0] + ' , ' + " ".join(token) + '\n')
の箇所。' , 'のように、カンマの前後に空白を入れないと正しく判定できなくなる。
なお
model = ft.train_supervised(r'PATH-TO-MODEL\model.txt', epoch=5, loss="hs")
の箇所について
epoch は訓練データを何度学習に用いるか、loss は損失関数の設定。loss の設定値はsoftmax, hs(Hierarchical Softmax), ns(Negative Sampling)がある。
このあたりで精度が変わってくるので、色々な値を試してみるのもといいと思う。
fastText の利用
今回は新たに来た問い合わせをtxt にして読み込んだ。
Predict.py
import fasttext as ft from janome.tokenizer import Tokenizer model = ft.load_model(r'PATH-TO-MODEL\fasttext.bin') tokenizer = Tokenizer() with open(r'PATH-TO-TARGET\target.txt', 'r', encoding='utf-8') as f: token = tokenizer.tokenize(f.read().replace('\n', ''), wakati=True) labels, probs = model.predict(" ".join(token), 5) for label, prob in zip(labels, probs): print(label, prob)
実行結果
__label__機能A 0.5012339353561401 __label__機能D 0.24753247201442719 __label__機能C 0.07739140093326569 __label__機能E 0.07420869171619415 __label__機能B 0.026388105005025864
実行結果の右側の数値が、fastText が予想した確率。
約50%の確率で機能Aだと思った。ということだ。
ちなみに実際に正解で、このときは人間でも判断に迷う問い合わせをあえて選んだので悪くない数字だ。他の分かりやすい問い合わせでは90%程度で正解を出してくれた。
なお
labels, probs = model.predict(" ".join(token), 5)
この箇所の、最後の数字で上位何件出すか決まる。
まとめ
わずか20行程度で自然言語処理を実装でき、高速かつ実用に耐える精度で分類可能なfastText。今回は問い合わせで使ったが、色々なことに応用ができそうだ。
まず自然言語処理を試してみたい、分類の自動化を試してみたいという方には非常に良い選択肢になるのではないだろうか。
コメント
コメントを投稿