テキスト自動分類の第一歩!fastTextを使った初心者向けガイド
この記事では、fastTextでテキスト自動分類に取り組んでみます。
「fastTextでテキスト分類がとりあえずできる状態」を目指して執筆しました。
機械学習でテキスト分類をする方法はいくらでもありますが、fastTextを使うメリットは以下のとおりです。
- 省メモリで高速に動作する
- GPUなしで動作する
- 単語ベクトルを自動で作ってくれる (別のツールで作る必要がない。)
このように、fastTextは、初心者にとっつきやすい文章分類ツールといえます。
また、実際のサービス運用を考えたときにも大きなメリットになるので、実用性の高いツールであるといえます。
環境構築
今回の検証で使うfastTextをインストールします。
fastTextはC++とpythonの2つのインタフェースが用意されています。
機械学習を使う人の多くがpythonを使うので、今回はpython版をインストールします。
pip install git+https://github.com/facebookresearch/fastText.git@v0.9.2
2020/08/25時点で最新となる、v0.9.2 を指定してインストールしました。
ちなみに、日本語の文章を検証するときは、MeCab
やSudachi
などのトークン化ツールが必要です。
今回は、英語の文章で学習するので、インストール不要です。
検証用の文章データの取得
とりあえず、fasttextが使える状態を目指すわけなので、データサイズが少なめの文章を選びました。
今回は、NLP100本ノック2020でも使われていた、News+Aggregatorを使うことにします。
ダウンロードリンクからzipファイルを取得して展開してください。
以下のコマンドで実施することもできます。
wget https://archive.ics.uci.edu/ml/machine-learning-databases/00359/NewsAggregatorDataset.zip
unzip NewsAggregatorDataset.zip
2pageSessions.csv
と newsCorpora.csv
の2つのファイルが展開されますが、今回は、newsCorpora.csv
を使います。
学習用とテスト用に分離
newsCorpora.csv
を学習用とテスト用データに分離します。
import pandas as pd
import csv
from sklearn.model_selection import train_test_split
news_corpora = pd.read_table('newsCorpora.csv', header=None,quoting=csv.QUOTE_NONE)
train, test = train_test_split(news_corpora, test_size=0.2, random_state=0)
分離した後は、下記のようにファイル保存します。
学習に使うのは、タイトルとカテゴリなので、2つのカラムだけを保存します。
train[[1, 4]].to_csv('train.tsv', sep='\t', index=False, header=None)
test[[1, 4]].to_csv('test.tsv', sep='\t', index=False, header=None)
train.tsv
とtest.tsv
は、以下のようなデータが保存されているはずです。
'X-Men: Days of Future Past' owns the holiday weekend e
KEEPING UP WITH THE KARDASHIANS: NEW WEDDING DETAILS e
Ruble Drops With Bonds as Gas Talks Fail: Russia Reality Check b
'Divergent' Stars Shailene Woodley & Theo James on Film's Soundtrack e
fasttext形式に加工
上で作成した学習用とテスト用のデータをそれぞれ、fastText形式に保存します
# 学習データを加工
with open('train.tsv', 'r') as f_in, open('train_fasttext.txt', 'w') as f_out:
for row in f_in:
text, label = row.strip().split('\t')
f_out.write('__label__{} {}\n'.format(label, text))
# テストデータを加工
with open('test.tsv', 'r') as f_in, open('test_fasttext.txt', 'w') as f_out:
for row in f_in:
text, label = row.strip().split('\t')
f_out.write('__label__{} {}\n'.format(label, text))
下記のような形式で保存できていれば、OKです。
__label__e 'X-Men: Days of Future Past' owns the holiday weekend
__label__e KEEPING UP WITH THE KARDASHIANS: NEW WEDDING DETAILS
__label__b Ruble Drops With Bonds as Gas Talks Fail: Russia Reality Check
見ての通り、fastTextのデータは、__label__{ラベル名}
テキスト の形式で作ります。
今回は、ラベル名がニュースのカテゴリ、テキストがニュートのタイトルになります。
なお、カテゴリは、b = business, t = science and technology, e = entertainment, m = healthの4つがあります。
分類器の学習
いよいよ、分類器の学習です。
といってもコードは、とてもシンプルです。
import fasttext
model = fasttext.train_supervised(input="train_fasttext.txt")
model.save_model("news_corpora.bin")
学習時間は、Colaboratoryで10秒程度でした。
小さめデータで学習しているというのもありますが、かなり高速に学習してくれます。
分類器でカテゴリを推論
ためしに、Dutch arrest girl for threatening tweet to American Airlines
という記事タイトルを推論してみます。
カテゴリeに分類されるのが正解です。
ret = model.predict("Dutch arrest girl for threatening tweet to American Airlines")
print(ret) # (('__label__e',), array([0.91577011]))
期待どおり、カテゴリ e
が返却されました。
arrayで返却される0.91577011は、確率値を表します。
上の場合、カテゴリe である確率が0.91577011であることをしめします。
ちなみに、予測結果を2つ以上返すこともできます。
ret = model.predict("Dutch arrest girl for threatening tweet to American Airlines")
print(ret) # (('__label__e', '__label__b'), array([0.91577011, 0.07166039]))
予測するカテゴリが1つでない場合に使えそうです。
分類器を評価
さいごに分類器を評価します。
分類器の評価も簡単で、下記のコードで事前に作ったテストデータに対する評価が出ます。
ret = model.test("test_fasttext.txt")
print(ret) # (84588, 0.931136804274838, 0.931136804274838)
タプルの先頭が 84588 で、これがテストデータの件数です。2番目と3番目がそれぞれprecision, recall になります。
とくにパラメータチューニングとか実施していませんが、結構高めの精度が出ました。
学習時のハイパーパラメータを調整すれば、違う結果が出てきます。
例えば、epoch=10
にしてみるとこんなかんじです。
ret = model.test("test_fasttext.txt")
print(ret) # (84588, 0.9389629734714143, 0.9389629734714143)
若干ですが、epoch=5
のときよりも高い精度が出ましたね。
学習時のハイパーパラメータは以下に一覧があるので、興味があればいろいろと試してみてください。
おわりに
どうでしたか?
できるだけ機械学習初心者でもすぐに試せるレベルで書いてみたつもりです。
ちなみに、今回の検証ではテキストクレンジグなどの前処理は実施していません。
実施すれば、精度が多少上がるはずなので、興味がある方はトライしてみてください。
Discussion