はじめに
仕事で、慣れないNLP(自然言語処理)の必要が生じたため、これを機に調べたことをまとめます。
Word2Vecが出てきて以来、単語のベクトル化が簡単になり、文(センテンス)のベクトル化も、いろいろと手法が出てきているが、文章・文書(文のかたまり)のベクトル化は、まだまだ難しいだろうと勝手に思い込んでいたのですが、私が勉強不足だっただけで、様々な手法が開発されており、自分で試したところ、想定していたよりいい結果が出たので、まとめることにしました。
手法を開発した先人たちに、深く感謝します。
自分で手を動かす前に、ネットで調べた際に、参考になる優れた記事にたくさん出会いましたが、下記の記事はその中でも、特に感銘を受けました。
https://qiita.com/nekoumei/items/1f5ec09e422a4be99810
やっていることは、各手法のシンプルな比較なのですが、BOWやTF-IDFのような、古典的とも言える手法も含めて、たくさんの手法を比較しておられます。
特に感銘を受けたのは、BOWとTF-IDFが、より新しい手法を凌駕して、圧倒的に優れた結果を出したことです。
このサイトの作者様も書かれていますが、文書分類という検証の性質上、特定の単語を含むかどうかが、大きな意味を持つだろうということを考えれば、当たり前のような気もしますが、実際のデータを使って、具体的な数値で手法間の差を表したことは、(私にとっては)非常に大きい意味を持ちます。
とにかく、BOWとTF-IDFの結果に驚きました。
使われているデータセットは、トピック間の類似度が低いので、もっと類似度の高い(似通った)トピックでの分類の場合は、(他の手法との比較という意味において)また、違った結果になるだろう、ということは想像できますが、文書分類の課題をやる時には、大いに試す価値があると思いました。
検証 1
せっかくなので、上記の記事に、少しだけ追加で検証を行いました。
内容は、下記の通りです。
検証 1-1
分ち書きに使われているMeCabをJuman++に変更して、変化があるかを確認しました。
モデルは、元の記事で、結果が良かったものに絞って実施しました。
結果
BoW
MeCab | Juman++ | |
---|---|---|
fold 1 | 0.95658 | 0.96268 |
fold 2 | 0.95725 | 0.96200 |
fold 3 | 0.95858 | 0.95587 |
fold 4 | 0.95247 | 0.95790 |
fold 5 | 0.96062 | 0.96266 |
TF-IDF
MeCab | Juman++ | |
---|---|---|
fold 1 | 0.96065 | 0.95929 |
fold 2 | 0.94572 | 0.94436 |
fold 3 | 0.94908 | 0.95247 |
fold 4 | 0.95247 | 0.95247 |
fold 5 | 0.94908 | 0.95587 |
SWEM-MAX
MeCab | Juman++ | |
---|---|---|
fold 1 | 0.92062 | 0.90976 |
fold 2 | 0.92198 | 0.90637 |
fold 3 | 0.90427 | 0.91174 |
fold 4 | 0.90291 | 0.90563 |
fold 5 | 0.92668 | 0.91785 |
考察
MeCabからJuman++に変更して、結果が向上したものと劣化したものがあります。
一概に、どちらがいいとは言えなさそうです。
また、どちらにしても、大きな差はなさそうですが、処理時間を考えると、(個人的には)このケースでは、MeCabの方が、総合的には優れていると言えそうです。
検証 1-2
SWEMに、MIN+MAXとMEAN+MAXを追加
(SWEMについては、こちらの記事 https://yag-ays.github.io/project/swem/ が分かりやすいです。)
SWEMにて、MINとMAX(または、MEANとMAX)をconcatしたものを使用します。
MIN、MEAN、MAXの単体では、300次元のベクトルになりますが、300次元のMIN(または、MEAN)と300次元のMAXを結合して、600次元のベクトルとして、分類(LGBM)にかけています。
(fasttextのpretrained modelより、通常のw2vの方が結果が良かったので、そちらを使用しています。)
SWEM-MIN+MAX
結果
MeCab | Juman++ | |
---|---|---|
fold 1 | 0.93012 | 0.92537 |
fold 2 | 0.92537 | 0.91926 |
fold 3 | 0.92803 | 0.92735 |
fold 4 | 0.92871 | 0.92057 |
fold 5 | 0.92871 | 0.92260 |
考察
BoWやTF-IDFには及びませんが、SWEM MAXよりは、数値が向上しました。
MeCabとJuman++の比較については、MeCabの方が優れた結果となりました。
SWEM-MEAN+MAX
結果
MeCab | Juman++ | |
---|---|---|
fold 1 | 0.93283 | 0.92469 |
fold 2 | 0.93147 | 0.92469 |
fold 3 | 0.92124 | 0.92871 |
fold 4 | 0.92803 | 0.91853 |
fold 5 | 0.93754 | 0.93957 |
考察
SWEM-MIN+MAXより、わずかに数値が向上しました。
BoWやTF-IDFには及びませんが、かなりいい数値が出ています。
MeCabとJuman++の比較については、MeCabの方が優れた結果となりました。
検証 1-3
ベクトル化された文書を分類するのに使われているLGBMを、SVMに変更して、変化があるかを確認
結果
SWEM-MIN+MAX-MeCab
LGBM | SVM | |
---|---|---|
fold 1 | 0.93012 | 0.90027 |
fold 2 | 0.92537 | 0.88941 |
fold 3 | 0.92803 | 0.89545 |
fold 4 | 0.92871 | 0.87644 |
fold 5 | 0.92871 | 0.88458 |
考察
SVMの方は、大きく数値が低下してしまいました。
やはり、LGBM強し、ということでしょうか。
検証2
BERTを使った文書分類
さて、ここからが、いよいよ本題です。
先程までの手法は、あくまで単語のベクトルの集合を元に、文章のベクトル化を行なっていましたが、BERTでは、文をベクトル化することができます。
そこで、そのベクトル化された文の集合から、SWEMを使って、文章のベクトルを生成し、文書分類を行なってみたいと思います。
また、せっかくなので、分かち書きを、MeCabとJuman++のそれぞれで実施します。
こちらの検証を実施するにあたっては、下記のサイトの実装を参考にさせて頂きました。
https://orizuru.io/blog/machine-learning/bert/
https://yag-ays.github.io/project/pytorch_bert_japanese/
深く感謝申し上げます。
まずは、ベクトル化したものをtSNEで可視化します。
MeCab | Juman++ | |
---|---|---|
SWEM-MAX | ![]() |
![]() |
SWEM-MIN | ![]() |
![]() |
SWEM-MEAN | ![]() |
![]() |
SWEM-MIN+MAX | ![]() |
![]() |
SWEM-MEAN+MAX | ![]() |
![]() |
SWEM-MIN+MEAN+MAX | ![]() |
![]() |
正直、どれも、あまり違いがなさそうです。
では、数値を見てみます。
RandamForest
(*ハイパーパラメータはすべて指定なしです。)
MeCab (1回目) |
MeCab (2回目) |
Juman++ (1回目) |
Juman++ (2回目) |
|
---|---|---|---|---|
SWEM-MAX | 0.87788 | 0.87290 | 0.88150 | 0.88692 |
SWEM-MIN | 0.87833 | 0.88421 | 0.87743 | 0.87924 |
SWEM-MEAN | 0.87426 | 0.87788 | 0.88104 | 0.89009 |
SWEM-MIN+MAX | 0.88059 | 0.88421 | 0.89326 | 0.88240 |
SWEM-MEAN+MAX | 0.89823 | 0.90321 | 0.90909 | 0.91361 |
SWEM-MIN+MEAN+MAX | 0.90094 | 0.89733 | 0.90592 | 0.90954 |
考察
精度では、MeCabよりJuman++の方が、わずかに優っています。
このモデルの場合、Juman++、MeCabともに、SWEM-MEAN+MAXが最も数値がいいという結果になりました。
SVM
(*ハイパーパラメータはすべて指定なしです。カーネルはrbfです。)
MeCab (1回目) |
MeCab (2回目) |
Juman++ (1回目) |
Juman++ (2回目) |
|
---|---|---|---|---|
SWEM-MAX | 0.93080 | 0.93939 | 0.94437 | 0.94527 |
SWEM-MIN | 0.94301 | 0.93623 | 0.94166 | 0.94754 |
SWEM-MEAN | 0.93668 | 0.92899 | 0.93578 | 0.93894 |
SWEM-MIN+MAX | 0.94889 | 0.94346 | 0.94980 | 0.94211 |
SWEM-MEAN+MAX | 0.94799 | 0.94392 | 0.94754 | 0.94301 |
SWEM-MIN+MEAN+MAX | 0.94708 | 0.94166 | 0.95522 | 0.94889 |
考察
全体の精度では、やはり、MeCabよりJuman++の方が、わずかに優っていますが、SWEMの方式によって異なるなど、一概には言えない結果です。
このモデルでは、Juman++では、SWEM-MIN+MEAN+MAX(1回目)が最も数字がよく、MeCabでは、SWEM-MIN+MAX(1回目)が最も数字がいいという結果でした。
XGB
(*ハイパーパラメータはすべて指定なしです。)
MeCab (1回目) |
MeCab (2回目) |
Juman++ (1回目) |
Juman++ (2回目) |
|
---|---|---|---|---|
SWEM-MAX | 0.90909 | 0.92266 | 0.92130 | 0.92944 |
SWEM-MIN | 0.91407 | 0.91361 | 0.91949 | 0.92266 |
SWEM-MEAN | 0.89688 | 0.90050 | 0.90412 | 0.90683 |
SWEM-MIN+MAX | 0.92854 | 0.92809 | 0.92763 | 0.92583 |
SWEM-MEAN+MAX | 0.93487 | 0.91633 | 0.93216 | 0.93261 |
SWEM-MIN+MEAN+MAX | 0.92402 | 0.92356 | 0.92763 | 0.93894 |
考察
ここでも、全体の精度では、MeCabよりJuman++の方が、わずかに優っていますが、上記と同様に、SWEMの方式によって異なるなど、一概には言えない結果となりました。
このモデルでは、Juman++では、SWEM-MIN+MEAN+MAX(2回目)が最も数字がよく、MeCabでは、SWEM-MEAN+MAX(1回目)が最も数字がいいという結果になりました。
LGBM
(*ハイパーパラメータはすべて指定なしです。)
MeCab (1回目) |
MeCab (2回目) |
Juman++ (1回目) |
Juman++ (2回目) |
|
---|---|---|---|---|
SWEM-MAX | 0.91316 | 0.90683 | 0.91633 | 0.92628 |
SWEM-MIN | 0.91045 | 0.91633 | 0.91000 | 0.90502 |
SWEM-MEAN | 0.90005 | 0.91045 | 0.90592 | 0.91045 |
SWEM-MIN+MAX | 0.90592 | 0.91995 | 0.92266 | 0.92718 |
SWEM-MEAN+MAX | 0.92266 | 0.92221 | 0.92537 | 0.91814 |
SWEM-MIN+MEAN+MAX | 0.92763 | 0.91949 | 0.93623 | 0.93397 |
考察
やはり、全体の精度では、MeCabよりJuman++の方が、わずかに優っていますが、上記と同様に、SWEMの方式によって異なるなど、一概には言えない結果となりました。
このモデルでは、Juman++では、SWEM-MIN+MEAN+MAX(1回目)が最も数字がよく、MeCabでも、SWEM-MIN+MEAN+MAX(1回目)が最も数字がいいという結果になりました。
総論
BERTを使ったこの検証では、SVMが最も精度が高いという驚くべき結果となりました。
SVMの精度が高いということは、超平面で分離できているということなので、汎用性の高い、(比較的)理解の容易な、優れたモデルができているのではないかと推測します。
また、数値自体も、上記検証1のBoWやTF-IDFに準ずるような非常に高いものが得られていますが、BERTは、BoWやTF-IDFのような単純なモデルではなく、文脈を考慮した文のベクトル化をベースにしているので、より広範囲な状況で、有用な使い方ができるのではないかと思います。
「BERT恐るべし」です。
SWEMの方式としては、SWEM-MIN+MEAN+MAXが、最もいい数値を出すケースが多かったのですが、実施のたびに数値が変わり、必ずしも、SWEM-MIN+MEAN+MAXが最も優れているとも言えないようです。
また、SWEM-MIN+MEAN+MAXでは、次元数が多くなることを考えると、SWEM-MIN+MAXか、SWEM-MEAN+MAXがいい選択肢というケースもありそうです。
また、MeCabとJuman++の比較においては、純粋な精度だけの比較では、Juman++が優れているように見えますが、圧倒的な処理時間の差を考えると、よほど精度にこだわった場合でなければ、個人的には、MeCabの方が総合的に優れいているという印象でした。
以上、最後まで、お読み頂き、有り難うございました。