【N-gram】テキストをベクトルで表現するには | 自然言語処理
自然言語処理において、モデルへの入力はベクトルで与えることが想定されているので、テキストをモデルに変換する必要があります。
テキストをベクトルで表現するには、まず形態素解析などでテキストを単語に分割する必要があります。
形態素解析については、【自然言語処理】形態素解析で文章を単語に分けてみましょう。や【自然言語処理】単語の出現頻度を可視化させてみましょうをご覧くださいませ。
N-gramベクトル
N-gramとは、n個のトークン(単語)単位でテキストを分割する手法のことです。
n=1でユニグラム、n=2でバイグラム、n=3でトライグラム‥と呼んだりしています。
「私は、自然言語処理が大好きです。」 ユニグラム:私 は , 自然 言語 処理 が 大好き です 。 バイグラム:私は は、 、自然 自然言語 言語処理 処理が が大好き 大好きです です。
このようにテキストを分割した後は、ベクトル化する必要があります。
n=1のユニグラムの時のベクトル化の手法を、Bag of N-gramsを呼びます。
今回はその中でも、TF-IDFを使ってみます。
TF-IDF (term frequency inverse document frequency)
今回は日本語のテキストをベクトル化しようと思います。
今回使うN ~gramベクトルの手法は、tf-idfと呼ばれるものです。
tf-idfとは、term frequency inverse document frequencyの略であり、「単語の出現頻度」と「文書における頻度の逆数」を考慮します。
具体的には、「単語の出現頻度によって重みづけする+多くの文章に登場する単語の重要度を下げる」という考え方でテキストをベクトル化します。
ただ単に、カウントエンコーディングしただけだと、上のように[3,3,1,1,1,1]というベクトルが生まれますが、
tf-idfでは「人民」「の」など、単語自体が、単体のテキストではなく全体の文書のうちどれくらい出てくるかを考慮し、出現頻度が高いものの重みを下げます。
$$tf-idf(t,d)=tf(t,d)×idf(t,d)$$
$$idf(t,d)=log\frac{N}{1+df(t)}$$
Nは全文書数であり、df(t)は該当の単語が出現する文書の数です。
ここは厳密に覚える必要はないと思います。コードの解説に入ります。
janomeを使いますので、ローカルに入れていない方は、以下のコードをターミナルに入れてください。
pip install janome
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction.text import CountVectorizer
from janome.tokenizer import Tokenizer
#分かち書きの関数の定義
#日本語だからやる必要がある
t = Tokenizer(wakati = True)
まずは、諸々のラインブラリをインポートしてきます。
feature_extractionなので、特徴量を抽出する機能を持ちます。
英語とは違って、日本語はデフォルトで分かち書きがされていません。
ここで分かち書きの関数の定義を行います。
今回は、以下のようなテキストをベクトル化してみます。
自然言語処理が難しい原因の一つとして、その曖昧性が挙げられます。例えば、人によって括弧が半角だったり、一部をカタカナにしていたりします。この曖昧性がプログラミング言語と自然言語の大きな差です。この曖昧性によって、事前の前処理が多くなりがちです。
scikit-learnのTfidfVectorizerを使えば簡単に実装することができます。
TfidfVectorizerの引数は、分かち書きするためのメソッドを入れています。
この処理をしないと、日本語は句読点単位でしか認識できません。
試しにやってみるのもありです。
vectorizer = TfidfVectorizer(tokenizer=t.tokenize)
text = ["自然言語処理が難しい原因の一つとして、その曖昧性が挙げられます。例えば、人によって括弧が半角だったり、一部をカタカナにしていたりします。この曖昧性がプログラミング言語と自然言語の大きな差です。この曖昧性によって、事前の前処理が多くなりがちです。"]
tfidf = vectorizer.fit_transform(text)
vocab = vectorizer.get_feature_names()
pd.DataFrame(tfidf.toarray(),columns=vocab).round(2)
、 | 。 | い | が | がち | この | し | その | たり | だっ | … | 多く | 大きな | 差 | 性 | 括弧 | 挙げ | 曖昧 | 自然 | 言語 | 難しい | |
0 | 0.32 | 0.32 | 0.08 | 0.41 | 0.08 | 0.16 | 0.16 | 0.08 | 0.16 | 0.08 | … | 0.08 | 0.08 | 0.08 | 0.24 | 0.08 | 0.08 | 0.24 | 0.16 | 0.24 | 0.08 |
このように句読点や助詞の重みが抑えられました。
そもそも名詞だけ抽出したい場合は、事前に名詞だけのデータフレームを作るのもありです。
【自然言語処理】単語の出現頻度を可視化させてみましょうを参考にしてみてください。
特徴エンジニアリング
そもそもなぜテキストをベクトル化する必要があるのかというと、特徴量の選定のためです。
機械学習のアルゴリズムの性能が高くなるには、rawデータから有益な特徴量を抽出する必要があります。
これを特徴エンジニアリングと呼びます。
テキストを単語に分け、重要な単語を重みつけしてテキスト同士の類似度を測るなどするには、この「重みつけ」という行為が非常に重要になります。
現在話題にしているのは、この「重みつけ」の場面です。