Tfidfで文字をベクトル化してLightGBMで学習することができます。
性能重視ならBERTを使うべきですが、計算が重くGPUが必要です。
CPUで計算できるような簡単なモデルを作りたい場合は、今回の方法を使いましょう。

fetch_20newsgroups
モデルを作るために文字データが必要なので、scikit-learnにあるデータセットを使います。
from sklearn.datasets import fetch_20newsgroups
train_data = fetch_20newsgroups(subset = 'train')
valid_data = fetch_20newsgroups(subset = 'test')
“fetch_20newsgroups”は20グループに分けられた文字データセットです。
引数”subset”を”train”にすると学習データ、”valid”にすると評価データが得られます。
import pandas as pd
train = pd.DataFrame({"text" : train_data["data"], "target" : train_data["target"]})
valid = pd.DataFrame({"text" : valid_data["data"], "target" : valid_data["target"]})
print(train.shape, valid.shape)
train.head()

このように文字データとラベルが入った表ができるはずです。
文字を取り出してみましょう。↓
print(train["text"].values[0])

メールの文面みたいですね。
ラベルは”target”の列に入っており、7番です。
print(train_data.target_names)
print(train_data.target_names[7])
“target_names”にラベル名が入っています。合計で20クラスです。
7番目は”rec.autos”つまり車関係ということですね。
今回は“text”の文字データから”target”のラベルを予測しましょう。
tf-idf
なので、tf-idfで文字を数値化しましょう。
tf-idfの数学的な説明は私にはできませんので、ぜひ調べてみてください。
私は、単語の出現頻度とレア度をうまくベクトル化する手法程度に理解しています。
from sklearn.feature_extraction.text import TfidfVectorizer
sklearnの”feature_extraction”に”TfidfVectorizer”があります。
vectorizer = TfidfVectorizer(max_features = 1000)
X_train = vectorizer.fit_transform(train["text"].values)
X_valid = vectorizer.transform(valid["text"].values)
TfidfVectorizerの”fit_transform”で学習データ(train)に対応させます。
評価データ(valid)は本来未知のデータなのでtransformだけで変換してください。
“max_features”はデータの次元数です。列方向のデータサイズに関係します。
大きければ大きいほどデータの表現力が上がりますが、計算が重くなるので注意。
print(X_train.shape, X_valid.shape)
shapeで変換後のデータサイズを見てみましょう。
行方向はもともとのデータの行数のままで、列方向が”max_features”の数値と同じはずです。
以上で文字⇒数値の変換が完了しました。
モデル作成(LightGBM)
今回はLightGBMの多クラス分類モデルを作ります。

モデル作成手順は以下の通り。
②パラメータ設定
③学習
import lightgbm as lgb
“lightgbm”をインポートします。よくlgbと略されます。
train_set = lgb.Dataset(X_train, train["target"].values)
valid_set = lgb.Dataset(X_valid, valid["target"].values)
データをDataset形式に変換しました。
特徴量としてif-idf変換した数値ベクトルを、目的変数として”target”を渡してください。
次にパラメータを設定します。
params = {
"objective" : "multiclass",
"metric" : "multi_logloss",
"num_class" : 20
}
metric:評価指標。多クラスならmulti_logloss。
num_class:クラス数。今回は20。
最後にtrainで学習します。
model = lgb.train(
params = params,
train_set = train_set,
valid_sets = [train_set, valid_set],
num_boost_round = 300,
early_stopping_rounds = 10,
verbose_eval = 20,
)
early_stopping_rounds:指定した回数だけ性能が改善しないとストップ。
verbose_eval:結果を表示する頻度。

このように学習結果が出力されます。
lossが下がっているのでうまく学習が進んでいるとわかりますね。
予測結果
predictで予測できます。評価データを渡しましょう。
preds = model.predict(X_valid)
print(preds.shape)
予測値は各ラベルに該当する確率となっています。
なのでデータサイズは(元データの行数, ラベル数)にです。
preds = preds.argmax(axis = 1)
print(preds)
print("=" * 50)
print(valid["target"].values)

argmaxを列方向(axis = 1)に実行すると最も値が大きい列番号が出力されます。
つまり最も予測確率の大きいラベルを予測結果にするということです。
実際の正解データと比較すると同じ数値になっていますね。
正解率を計算してみましょう。↓
from sklearn.metrics import accuracy_score
acc = accuracy_score(valid["target"].values, preds)
print(acc)
“accuracy_score”をインポートします。
正解データと予測値を入れると正解率を計算してくれます。
だいたい60%強くらいかと思います。
max_featuresと予測精度
TfidfVectorizerの変換時に”max_features”を1000に設定しました。
この値を小さくすると列数が減り、学習が早くなる一方でデータの表現力が落ちます。
MAX_FEATURES = 100
vectorizer = TfidfVectorizer(max_features = MAX_FEATURES)
X_train = vectorizer.fit_transform(train["text"].values)
X_valid = vectorizer.transform(valid["text"].values)
train_set = lgb.Dataset(X_train, train["target"].values)
valid_set = lgb.Dataset(X_valid, valid["target"].values)
model = lgb.train(
params = params,
train_set = train_set,
valid_sets = [train_set, valid_set],
num_boost_round = 300,
early_stopping_rounds = 10,
verbose_eval = 20,
)
preds = model.predict(X_valid).argmax(axis = 1)
acc = accuracy_score(valid["target"].values, preds)
print(MAX_FEATURES, acc)
“max_features”を100にしました。
実行すると学習が早く終わり、正解率が30%くらいに下がっているかと思います。
一方で5000にすると正解率75%を超えました。
ちなみに”max_features”を設定しないデフォルトだと、列数は130107で正解率77%くらいです。
まとめ:自然言語処理モデルを作ってみよう
今回はtf-idfとLightGBMで自然言語処理モデルを作る方法を解説しました。
CPUで手軽に実装できる方法なのでぜひ試してみてください!
BERTを使いたい方は以下の記事をどうぞ。
>>【無料説明会あり】キカガクのAI人材育成コースで勉強する

コメント