今回は、fastTextライブラリを用いて、英語文章を教師データ有で学習し自動的にカテゴリーに分類する方法を紹介します。
はじめに
セキュリティ文章を読んでいて、CVEの説明に応じて決められたカテゴリーに分類する必要が出てきたので、自動化を考えました。そこで目を付けたのが、fastTextライブラリです。英語文章を教師ありの学習で分類する手法を学びます。
サンプルとして、映画のレビュー文から、ポジティブ/ネガティブの感想2種類に分類してみます。
環境作成
pythonを導入した環境で、以下のコンポーネントを設定します。
pipモジュールインストール
コード実行に必要なpythonライブラリモジュールをインストールします。
pip install pandas
pip install nltk
nltkデータダウンロード
文章の前処理に必要なnltkのデータを取得します。
> python
>> import nltk
>> nltk.download('all')
>> quit()
データの保存先は、%APPDATA%\nltk_dataです。ストレージが3GB超必要です。
fastTextインストール
fastTextのモジュールを公式サイトからダウンロードし、ローカルフォルダに展開します。次に下記コマンドを実行して、モジュールをインストールします。
cd /d {fastTextフォルダパス}
pip install .
pip install fastTextコマンドでは、途中でコンパイル処理が走るので使っていません。
サンプルデータ準備
サンプルデータとして、KaggleのIMDB Dataset of 50K Movie Reviewsを利用させていただきました。5万行のデータが存在します。
このデータは、各行ごとに”レビューコメント,気分(positive,negative)”という構成になっています。fastTextでは、トレーニングデータとして”__label__{分類ラベル} 分かち書きテキスト“を1行とするファイルが必要なので、fastTextに適合した形式(__label__気分 レビューコメント)に変換するコードを書きました。convert.txtというファイルを作成しています。
分かち書きは文節に区切られた文章のことで、nltkのlemmatizerと禁足文字除去および多少のデータクレンジングを施して、英語文章用を構成しました。
import pandas as pd
import nltk
from nltk.tag import pos_tag
import string
def lemmatize_sentence(_text, _stop_words):
lemmatizer = nltk.WordNetLemmatizer()
ret = []
for word, tag in pos_tag(nltk.word_tokenize(_text)):
if tag.startswith('NN'):
pos = 'n'
elif tag.startswith('VB'):
pos = 'v'
elif tag.startswith('RB'):
pos = 'r'
else:
pos ='a'
word = word.lower()
word = lemmatizer.lemmatize(word, pos)
if len(word) > 0 and word not in string.punctuation and word not in _stop_words:
ret.append(word)
return ret
if __name__ == '__main__':
stop_words = nltk.corpus.stopwords.words('english')
df = pd.read_csv('IMDB Dataset.csv', encoding='utf-8')
with open('convert.txt', mode='w', encoding='utf-8') as f:
for value in df.values:
review = value[0].replace('<br />', '').replace('""', '"').replace('.', ' ')
sentiment = value[1]
normalized = lemmatize_sentence(review, stop_words)
f.write('__label__{0} {1}\n'.format(sentiment, ' '.join(normalized)))
実行
学習用データファイル作成
上記で作成したconvert.txtを、トレーニング用(train.txt)、妥当性確認用(valid.txt)および結果確認用(test.txt)データファイルに4:0.9:0.1の行数で分割します。ここの比率は適当です。
分類テストと結果
トレーニングおよび妥当性を確認するコードを下記の様に作成しました。
トレーニングでは、上記で作成したtrain.txtとvalid.txtを使用し、オートマティックチューニングでハイパーパラメーターを決定しています。算出されたモデルデータは、review.modelファイルに保存しています。
import fasttext
if __name__ == '__main__':
model = fasttext.train_supervised(input='train.txt', autotuneValidationFile='valid.txt', autotuneDuration=600)
model.save_model('review.model')
> python train.py
Progress: 100.0% Trials: 17 Best score: 0.901222 ETA: 0h 0m 0s
Training again with best arguments
Read 5M words
Number of words: 118316
Number of labels: 2
Progress: 100.0% words/sec/thread: 552865 lr: 0.000000 avg.loss: 0.182361 ETA: 0h 0m 0s
結果確認のコードを下記に示します。モデルデータreview.modelをロードし、1000個ほどのサンプルが掲載されたtest.txtを用いて効果のほどを確認しています。
単独文字列を評価したい場合、コメントアウトされているpredictを使用すれば、判定可能です。
import fasttext
if __name__ == '__main__':
model = fasttext.load_model('review.model')
ret = model.test('test.txt')
print(ret)
# reserved.
# value = lemmatize_sentence(text, stop_words)
# ret = model.predict(' '.join(value))
# print(ret)
> python predict.py
(1001, 0.8961038961038961, 0.8961038961038961)
まとめ
精度89%ということで、まずまずの分類結果が得られたのではないでしょうか。
fastTextを使用すれば、コード作成も容易に自然言語を利用した文書分類を実行することが可能です。前処理やパラメーターを調整すれば更に確度を上げていくことが可能だと思われますし、分かち書き処理のライブラリを変更すれば日本語でも対応することができます。
以上、fastTextで自然言語処理による文書分類を体験する紹介でした。
コメント