はじめに
CatBoostではtext_featuresに生の文字列を渡すだけで、トークン化とベクトル化を内部で勝手にやってくれます。この記事では使い方と、内部で何をしているかを紹介します。データは20 newsgroupsの2カテゴリ(野球 vs 医療)を使い、catboost==1.2.10です。
データの中身
20 newsgroupsの2カテゴリ(rec.sport.baseball と sci.med)を読み込み、ヘッダ・署名・引用を除いた本文だけを使います。text列にメールの生本文がそのまま入っていて、labelは野球=0 / 医療=1です。
import pandas as pd
from sklearn.datasets import fetch_20newsgroups
cats = ["rec.sport.baseball", "sci.med"]
tr = fetch_20newsgroups(subset="train", categories=cats, remove=("headers", "footers", "quotes"))
te = fetch_20newsgroups(subset="test", categories=cats, remove=("headers", "footers", "quotes"))
df_train = pd.DataFrame({"text": tr.data, "label": tr.target})
df_test = pd.DataFrame({"text": te.data, "label": te.target})
print(df_train.shape)
print(df_train.head())
(1191, 2)
text label
0 I am looking for a source of American League b... 0
1 \nNot particularly *in* the World Series. Duri... 0
2 \nI have lived in the Boston area for 15 years... 0
3 \n\n\nIf you culture out the spirochete, it is... 1
4 \nThe Dodgers after one inning of play have co... 0
このtext列を、ベクトル化せずにそのままCatBoostへ渡します。
使い方
fitのtext_featuresにテキスト列の列名を渡すだけです。前処理は不要で、上のtext列をそのまま入れます。今回は文字列だけ渡していますが他の数値特徴量なども一緒に入れられるのが便利。
from catboost import CatBoostClassifier
model = CatBoostClassifier(iterations=200, learning_rate=0.1, depth=6, verbose=0)
model.fit(df_train[["text"]], df_train["label"], text_features=["text"])
acc = (model.predict(df_test[["text"]]).ravel() == df_test["label"]).mean()
print(round(acc, 4))
0.9193
前処理を書かずに、文字列を渡すだけで91.9%まで出ました。
内部で何をしているか
text_featuresに渡された列は、CatBoostが内部でトークン化し、Bag-of-Words(単語の有無)やbi-gramなどの数値特徴に変換してから、通常の木に入れています。トークナイザや辞書、特徴の作り方(tokenizers / dictionaries / feature_calcers)はパラメータで調整でき、既定でもそのまま動きます。ふだん手で書くベクトル化のステップを、fitの中に畳み込んでくれる、というのが実際にやっていることです。
注意点
- テキスト処理のぶん、テーブルデータだけのときより学習は遅くなります(今回は200本の木で約10秒)。
text_featuresに渡す列は文字列にしておきます。多クラス分類でも同じように使えます。
まとめ
- CatBoostは
text_featuresに生の文字列を渡すだけでテキストを学習でき、前処理を書かずに91.9%が出た - 内部ではトークン化とBag-of-Words / bi-gramへの変換をfitの中で行っている
- テキスト列とテーブル列を同じ
fitに渡せるので、混在データも1モデルで扱える