🦔

NLP・ベクトル化・Bag of Wordsとは

2024/03/19に公開

意味不コードを発掘!!

「PythonではじめるKaggleスタートブック」で以下のコードが書かれていたんですね。でもまったくの意味不明だったんですよ。コメントアウトのところは僕がめちゃめちゃ書き込んだんですけど笑

import pandas as pd
df = pd.DataFrame({'text': ['I like kaggle very much',
                            'I do not like kaggle',
                            'I do really love machine learning']})
from sklearn.feature_extraction.text import CountVectorizer


# CountVectorizer()を呼び出している。
#token_pattern:数える単語のパターンを指定している
#ここでは文字列長が1(I am a studentのIとか)の単語を処理対象に含めるという指定をしている
#こうしないと文字列長が2以上のものしか処理対象じゃなくなる
vectorizer = CountVectorizer(token_pattern=u'(?u)\\b\\w+\\b')

#vectorizerでdfのtextの単語の回数を数え、numpay.ndarrayに変換している
bag = vectorizer.fit_transform(df['text'])
bag.toarray()

んで出力がこれ。

array([[0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1],
       [1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0],
       [1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0]])

正直何が起こっているのかわけわかめ。

んでもってこれを実行すると

print(vectorizer.vocabulary_)

こうなる

{'i': 1, 'like': 4, 'kaggle': 2, 'very': 10, 'much': 7, 'do': 0, 'not': 8, 'really': 9, 'love': 5, 'machine': 6, 'learning': 3}

What!?って感じで意味不明。

整理しながら考える

前提

まずはこのコードで何をしたいのかを考える。そうすることで全体像が見えるので、一つ一つの処理の意味もわかってくる。
ここでは自然言語処理(Natural Learning Processing)という日本語とか英語とかを扱う言語(プログラミングは人工言語)に関するKaggleの課題に対応できるようにしよう!というものです。
そして重要なのが、自然言語はそのままでは機械学習アルゴリズムで扱えないということです。たぶん、型が違うみたいなものなのでしょう。なので、テーブルデータの特徴量のように(文字列を数字に変換してコンピュータが扱える形式にするといったように)意味のあるベクトルとしてみなす(ベクトル化)必要があります。つまりベクトル化とは、自然言語の単語それぞれになんらかの要素を与えて、機械学習アルゴリズムとして扱えるようにするということですね。

「前提」を踏まえると、、、

これらの前提を踏まえると以下のリストカッコ内の文字列は英語であり、自然言語なので、機械学習アルゴリズムで扱えないということがわかります。

df = pd.DataFrame({'text': ['I like kaggle very much',
                            'I do not like kaggle',
                            'I do really love machine learning']})

ではどうする?

なので、文字の特徴をできるだけ保持した状態で、何かしらの方法でベクトル化する必要が出てきます。
その方法の一つとして「Bag of Words」というのがあります。文で登場した単語の回数を数える方法です。
それがこちら。

from sklearn.feature_extraction.text import CountVectorizer


# CountVectorizer()を呼び出している。
#token_pattern:数える単語のパターンを指定している
#ここでは文字列長が1(I am a studentのIとか)の単語を処理対象に含めるという指定をしている
#こうしないと文字列長が2以上のものしか処理対象じゃなくなる
vectorizer = CountVectorizer(token_pattern=u'(?u)\\b\\w+\\b')

#vectorizerでdfのtextの単語の回数を数え、numpay.ndarrayに変換している
bag = vectorizer.fit_transform(df['text'])
bag.toarray()

出力がこちら。この出力で文で登場した単語の回数を数えているということなのです。

array([[0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1],
       [1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0],
       [1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0]])

例えば、[0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1]はインデックス番号1、2、4、7、10に値する単語が文に含まれているということです。

具体的にはtoken_pattern パラメータによって単語のパターンが設定されています。一回ChatGPTに質問した時、Unicodeうんぬんって話がされていたので、それを用いて文字と文字に割り当てた番号を対応させて、「インデックス1は〇〇」、「インデックス2は▲▲」ってやってるんでしょうかね。

Unicodeとは

Unicode(ユニコード)とは
「符号化文字集合」と呼ばれるもののひとつ。
もう少し噛み砕いて書くと
文字コードの話で出てくる用語のひとつ
であり
コンピュータさんが使う「『文字』と『文字に割り当てた番号』の対応表」のひとつ
です。

引用:https://wa3.i-3-i.info/word11422.html

そんで以下を実行すると

print(vectorizer.vocabulary_)

このような出力になりました。

{'i': 1, 'like': 4, 'kaggle': 2, 'very': 10, 'much': 7, 'do': 0, 'not': 8, 'really': 9, 'love': 5, 'machine': 6, 'learning': 3}

つまりここでは

'単語':'インデックス番号'

を示しているということになりますね。

ただ「Bag of Words」って苦手なことがあるんですよね。例えば文の特徴を知りたい!というニーズに対してIといっためちゃめちゃ頻繁に使われるのより、Kaggleとかの方が単語としては珍しくて、文お特徴を捉えられそうですよね。

この問題を解消するのが「TF-IDF」です。

感想

いや〜よかったですね。この記事を書きながら、コードリーディングをちゃんとできたので、非常に役立ちたました。この環境をあたえてくださっているZennさんには感謝です。

なんか勉強中に思ったのが、「これって果たして自分のゴールに直結しているのことなのか?」ってことなんですよね。僕のゴールは「今年中にKaggleでメダルを取る」ことなのですが、そのゴール達成に対して果たして今やっている勉強は意味があるのか?ということですね。今学んでいることは実際のKaggleコンペでは使わないかもしれないですし、そもそももうコンペ出場しているころには忘れていますよね。なので、とりあえず簡単そうなコンペから始めて行って実践をとおしてやっていくのが一番身になるし、成果につながるしでいいことづくしなのではないか?と思っているわけです。ってわけで、本書ももうすぐ読了しそうなので、とりえず読了したらSIGNATEとかの練習問題をやってみようと思います。

Discussion