言語AIの進化史⑦トークン化とTF-IDF
前回は、クロード・シャノンのn-gramを紹介しました。今回は、トークン化とTF-IDFについて解説します。
本題に入る前に、次の2つの文章を比べて下さい。
男は犬を撫でた。
男は犬を噛んだ。
この2つの文章は、最初の部分が同じですが、後半の単語の選択により意味が大きく異なります。これを確率的に理解してみましょう。
両方とも「男は犬を」という同じ文字列で始まりますが、1番目の文章と比べると、2番目の文章はかなり出現確率が低い(珍しい)でしょう。これは「男は犬を」に「噛」が続く確率(可能性)が低いからです。
ただし、我々は何の文脈も持たずに判断しています。
仮に、「犬に襲われて倒れたが必死に抵抗して」という文脈があるならばどうでしょうか。
次の2つの文章を比べて下さい。
犬に襲われて倒れたが必死に抵抗して、男は犬を撫でた。
犬に襲われて倒れたが必死に抵抗して、男は犬を噛んだ。
「(襲われている)男」が「犬を撫でた」としたら、ちょっと変な感じがします。
よって、この文脈を与えられた条件下では、2番目の文章の方の確率が高くなるでしょう。逆に、1番目の文章の方の確率は低くなるべきです。
つまり、前のテキストを条件となって、その後に続くテキストの出現確率が変化しています。
このようなテキスト間の依存関係は、シャノンのn-gramによる条件確率のアプローチを使えばモデル化できそうです。そして、あらゆる条件(複数の文字)の次に来る文字の確率分布を学習できれば、文章の生成や分類が可能になるでしょう。
実際に、n-gramのアプローチはその後の確率的言語モデルの発展に貢献しました。前回の記事で紹介したように、n-gram的なアプローチがスパム・フィルタリングやテキスト分類などに応用されました。
しかし、シャノンのn-gramは文字(アルファベット)単位での処理を行います。これは、彼の目的はテキストの文字列の情報量の計算して効率よく伝達するためにn-gramを使用していたからです。つまり、文章の意味の理解は関係ありません。
一方、言語モデルの目的は言語の理解や生成なので、ある程度の意味を持つ要素を使って文章の確率分布を解析する方が効率が良くなります。
例えば、「dog」をアルファベットに分解し、「d」と「o」と「g」が並んだシーケンスと捉えるのと、「dog」を一つの意味的な塊として処理することの違いを考えて下さい。前者は一文字をシンボルとしていますが、後者は意味のある要素をシンボルとしています。意味を理解するためなら後者の方が効率的でしょう。
ただし、ここで文章を単位要素に分解するルールの必要性が生じます。
また、この単位要素はさまざまな文書や文章に渡って共通のものであるべきです。さもなければ、テキストの分類や比較などに一貫性を持たせることができません。
このため、まずは大量のテキストを集めてデータベース化します。このようなテキストのデータセットをコーパス(Corpus)と呼びます。そして、コーパス内のテキストを単位要素に分割します。この単位要素をトークンと呼び、テキストを処理してトークンへと分割する処理のことをトークン化(Tokenization)と呼びます。
トークン化によってコーパスからの大量のテキストはトークンのシーケンス(順番に並べたもの)へと変換されます。そうして得られたトークンの集まり対して統計的な処理を行うことで、文書や文章の特徴を数値化して表現するTF-IDF(Term Frequency-Inverse Document Frequency)という手法が1970年代ごろに発展しました。
コーパスのトークン化
コーパスのトークン化は言語モデルの学習においての「前処理」的なステップです。これをやっておかないとトークンを利用した学習が行えません。
初期の言語モデルのために行われたトークン化は、以下のような処理を含みます。
テキストの分割
小文字変換
不要な文字の削除
ステミング
レンマ化
ストップワードの排除
数値化
(なお、ここでは英語を念頭に置いています)
以下に各ステップを解説します。
テキストの分割
トークン化の最初のステップは、テキストを意味のある単位に分割することです。この単位は単語、サブワード、または文字にすることができます。最も一般的なのは、単語単位のトークン化です。
以下によく使われる例を紹介します。
"The quick brown fox jumps over the lazy dog."これを次のように分解します。
["The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"]Pythonを使えば、文字列を空白(スペース)で分割するのは簡単です。あとで述べるようにドット(".")などの(不要と考えられる)文字は取り除きます。
小文字変換
テキストをすべて小文字に変換することもよく行われました。大文字と小文字の違いによる(不要と考えられる)バリエーションを減らす効果があります。
極端な例として次のようなテキストがあるとします。
"The quick Brown Fox."これは次のように小文字化され分割されます。
["the", "quick", "brown", "fox"]Pythonなら、文字列に対して lower() を呼び出すだけですね。
不要な文字の削除
前述したように、句読点や記号など、モデルにとって(不要と考えられる)文字を取り除くことがあります。
例えば、感嘆符(!)が取り除かれます。
"Hello, world!"以下のように分割されます。
["hello", "world"]Pythonなら、正規表現(import re)で処理できます。
ステミング
ステミング(Stemming)は、単語をその語幹に変換する手法です。Stemとは幹の意味です。枝葉を除外して共通の形にします。
異なる形態の単語(動詞の過去形や複数形など)を統一することで、語彙の数を減らし、モデルの学習を効率化します。
例えば、以下の3つの単語を全て"run"に統一します。
"running", "runner", "ran" --> "run"他の例として次の2つの単語を全て"studi”に統一します。
"studies", "studying" --> "studi"ステミングは単純なルールベースの方法で、接尾辞や接頭辞を取り除くことにより、単語をその語幹に変換します。アルゴリズムは単純で高速ですが、文法や意味を考慮しないため、単語が不完全な形に変換されることがあります。
これには専用のライブラリであるNLTK(Natural Language Toolkit)の Porter Stemmer などを利用します。
レンマ化
レンマ化(Lemmatization)は、単語をその基本形(辞書形)に変換する手法です。ステミングと似ていますが、より正確に単語の意味を保持しながら統一します。例えば、動詞は原形に、名詞は単数形に変換されます。
ステミングの例と比較すると次のようになります。
"runner" --> "runner" # 名詞
"running", "ran" --> "run" # 動詞
"studies", "studying" --> "study" # 動詞見てわかる通り、レンマ化では、意味と文法に基づいて変換されています。
"runner" は名詞であり、その基本形も "runner" であるため、レンマ化を適用しても変化しません。これに対して、"running" や "ran" のような動詞の形は、レンマ化によって "run" という基本形に変換されます。
ストップワードの排除
一般的に頻出するが、文の意味に大きな影響を与えない単語(例: "and", "the", "is")を除去することがあります。
特に文章全体としての統計的性質によって判断を行う文章の分類などでは、どのような文章でも頻繁に使われるような単語は除外されます。
例えば、"the"という単語が文章の30%を占めたとしてもその文書の感情分析などにはあまり役に立たない(不要と考えられる)ケースです。
"This is a simple example."ここで、"This", "is", "a"が不要だとすると、このテキストの分割結果は以下になります。
["simple", "example"]ストップワードを処理するには、ストップワードのリストに照らし合わせて処理するものと処理しない(ストップ)するものを判断します。
NLTKなどには、標準でストップワードを処理する機能が備わっています。また、自分で独自のストップワードを準備することも可能です。
(不要と考えられる)について
トークン化における幾つかの処理を説明の中で、何度か(不要と考えられる)という形容を使いましたが、これには「人間が考えて不要かどうかを決めること」という意味を込めています。
文章の特性やタスクなどによって判断が変わってくるのでハイパーパラメータや設定の部類になります。
Bag-of-Words(BoW)
TF-IDFについて解説する前に、Bag-of-Words(BoW)について解説します。
「bag of words」という名称は、言語学では遅くとも1950年代ごろに使われていました。これは(言葉の順番を考えない)単なる言葉の集まりという意味です。
「bag of words」の意味を継承するBoWの手法では、トークンの並び順を考えずに、各トークンの出現頻度という統計量だけをを利用して文書や文書の特徴を表現します。
簡単な例で説明します。
コーパスの準備
まず、コーパス(いくつかの文書)を準備します。ここでは、3つの短い文書を例に取ります。
文書1: 「私は犬が好きです」
文書2: 「私は猫が好きです」
文書3: 「犬と猫は素晴らしい」
トークン化
次に、各文書をトークンに分割します。これがトークン化の処理です。
文書1: ["私", "は", "犬", "が", "好き", "です"]
文書2: ["私", "は", "猫", "が", "好き", "です"]
文書3: ["犬", "と", "猫", "は", "素晴らしい"]
語彙の作成
コーパス全体で登場するすべてのトークンのリスト(語彙)を作成します。
語彙: ["私", "は", "犬", "猫", "が", "好き", "です", "と", "素晴らしい"]
なお、プログラミングや自然言語処理の文脈では、語彙をディクショナリ(dictionary)または ボキャブラリ(vocabulary)と呼んだりします。
英語のvocabularyの訳が語彙なので「ボキャブラリ」という呼び名は自然です。
一方で、「ディクショナリ」という呼び名は、トークンをキーとして統計的な数値や他の関連情報を値として格納するデータ構造を指すことが多いです。例えば、トークンの出現頻度やインデックスを保存するために使われます。
文書ごとにBoWベクトルを作成
各文書を語彙に基づいてBoWベクトルに変換します。BoWベクトルの各要素は、トークンの頻度(文書に何回出現したか)を表します。
文書1: ["私", "は", "犬", "が", "好き", "です"]
ここで語彙にある各トークンの頻度は以下になります。
"私":1回
"は":1回
"犬":1回
"猫":0回
"が":1回
"好き":1回
"です":1回
"と":0回
"素晴らしい":0回
よって、この文書のBoWベクトルは以下になります。
文書1のBoWベクトル: [1, 1, 1, 0, 1, 1, 1, 0, 0]
同様に文書2のBoWベクトルを計算します。
文書2: ["私", "は", "猫", "が", "好き", "です"]
BoWベクトル: [1, 1, 0, 1, 1, 1, 1, 0, 0]
文書3のBoWベクトルも計算します。
文書3: ["犬", "と", "猫", "は", "素晴らしい"]
BoWベクトル: [0, 1, 1, 1, 0, 0, 0, 1, 1]
BoWで機械学習
ベクトル化された各文書をここに再掲します。
"文書1": ["私", "は", "犬", "が", "好き", "です"] --> [1, 1, 1, 0, 1, 1, 1, 0, 0]
"文書2": ["私", "は", "猫", "が", "好き", "です"] --> [1, 1, 0, 1, 1, 1, 1, 0, 0]
"文書3": ["犬", "と", "猫", "は", "素晴らしい"] --> [0, 1, 1, 1, 0, 0, 0, 1, 1]このベクトルは、単語の出現頻度に基づいて文書を数値で表現したものであり、以下のように利用できます。
類似度計算: 文書1と文書2のベクトルが似ているかを比較することで、両者がどれだけ似ているかを判断できます。文書1と文書2はベクトルが似ているため、似ていると評価できます。しかし、文書1と文書3はあまり似ていません。
テキスト分類: 各文書のBoWベクトルを入力として感情分析やテキスト分類のタスクを行う機械学習モデルに活用できます。分類モデルとしては、ロジスティック回帰、ナイーブベイズ分類器、サポート・ベクトル・マシン(SVM)などがあります。
BoWとn-gramを組み合わせる
BoWは、テキスト分類においてテキストを数値ベクトルに変換するための基本的な手法として広く使われました。この手法により、機械学習モデルは文書を数学的に扱うことができるようになり、様々なテキスト分類タスクに応用されました。
ただし、BoWはトークンの順序や文脈を考慮しないため、シーケンスからの意味的なニュアンスが失われるという限界もあります。つまり、異なる文脈で使われる同じ単語の違いを捉えることが難しいという欠点があります。
そこでn-gramの手法をトークンに当てはめてBoWと組み合わせることが行われました。
つまり、n-gramで得られる連続したトークンを特徴量として扱います。これにより、文脈や単語の順序情報を部分的に捉えることができます。
簡単な例で説明します。
まず、語彙として先ほどと同じ ものを使います。
語彙:["私", "は", "犬", "猫", "が", "好き", "です", "と", "素晴らしい"]を使います。
文章として以下が与えられているとします。
文書:「私は犬が好きです」
この文章をトークン化してBoWベクトルを計算します。
トークン化:[ "私", "は", "犬", "が", "好き", "です" ]
BoWベクトル:[1, 1, 1, 0, 1, 1, 1, 0, 0]
さらに、バイグラムの語彙が次のようになっているとします。
バイグラムの語彙:[ ("私", "は"), ("は", "犬"), ("犬", "が"), ("が", "好き"), ("好き", "です") , ("は", "猫"), ("猫", "が"), ("犬", "と"), ("と", "猫"), ("猫", "は"), ("は", "素晴らしい") ]
トークン化された文章をバイグラムで変換し、BoWベクトルを作ります。
バイグラム:[ ("私", "は"), ("は", "犬"), ("犬", "が"), ("が", "好き"), ("好き", "です") ]
BoWベクトル: [1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0]
こうしてできた2種類のBowベクトルを連結して一つの入力とし機械学習を行います。
入力ベクトル:[1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0]
このようにバイグラム(あるいはもっと高次なn-gram)を利用すれば、文書の中での単語の並びや文脈の違いを捉えることができ、テキスト分類や情報検索の精度を向上させることができます。
つまり、より豊かな文脈情報を反映させることが可能になります。
BoWの問題点
BoWでは、各単語の出現頻度がベクトルとして表現されますが、頻出単語が重要であるとは限りません。
例えば、英語で頻繁に登場する「the」や「is」などの単語が多く含まれる文書が、必ずしも他の文書と関連が深いとは言えません。よって、ストップワードを排除するといった処理が重要となります。
ただし、ストップワードだけだと、多くの文章に存在するが特徴量としてはしてはあまり意味の無いトークンを含めてしまいがちです。
つまり、コーパス全体に広く出現する一般的なトークンには低いスコアを割り当てるといった工夫が必要となります。
そこでTF-IDFが登場します。
TF-IDFの仕組み
TF-IDF (Term Frequency-Inverse Document Frequency)は、BoWと同じように基本的にはトークンの順番は考えません。各トークンに対して統計的な数値を計算して比較や機械学習の入力のために使います。
ただし、TF-IDFは文章の各トークンを頻度ではなく、統計的なスコア(重み付け)によって評価します。
このスコアは、次の二つを考慮した量です。
トークンが文書内でどれだけ頻繁に登場するか
トークンが他の文書でどれだけ頻繁に登場するか
多くの文章に頻繁に登場するトークンは一般的であり、文書の特徴量としてはあまり役に立たないので低いスコアを与えられます。
逆、他の文書ではあまり見られないトークンがある文書では頻繁に登場する場合、そのトークンには高いスコアが与えられます。こうして、その文書にとって特有で重要なトークンとして認識されます。
以下にTF-IDFの用語を説明します。
単語の頻度:TF
TF(Term Frequency)は、ある単語が特定の文書内でどれだけ頻繁に登場するかを測る指標です。特定の単語が文書内に出現する回数を、その文書内の総単語数で割ったものです。
例えば、文書Aにおいて「cat」が3回出現し、文書Aの総単語数が100の場合、TFは$${3/100 = 0.03}$$になります。
ある文書内で頻繁に出現するトークンはTFの値が高くなります。これによって、TFの値が高いトークンは文書において重要である可能性があることになります。
しかし、TFだけだと一般的な(どの文書にも出現する)トークンを重要だと取り違える可能性もあります。
そこでIDFが登場します。
逆文書頻度:IDF
IDF(Inverse Document Frequency)では、多くの文書に出現する一般的なトークンには低いスコアが与えられ、少数の文書にしか登場しない珍しいトークンには高いスコアが与えられます。
計算方法としては、コーパスにおける全文書数を、そのトークンが出現する文書数で割り、その対数を取ります。
例えば、コーパスが1000の文書で構成され、「cat」が100文書に登場する場合、IDFは常用対数(底が10)を使うと以下になります。
$$
\log_{10}(1000/100) = \log_{10}(10) = 1
$$
この値は、一般的なトークンでは0へ向かって小さくなり、文書に固有なトークンでは大きくなります。よって、文書に固有なトークンはより高いスコアを与えられます。
なお、対数を取るのは文書の数が多い場合に、特定のトークンのIDFの値が大きくなりすぎないようにするためです。つまり、対数を取ることで特定のトークンが異常に高い影響を持つのを防ぎます。
IDF(逆文書頻度)の概念が難しいと感じる場合、まずはトークンのコーパス全体における出現確率を考えると直感的な意味が掴みやすいかもしれません。
具体的には、トークンが出現する文書の数をコーパス全体の文書数 N で割って出現確率を計算します。多くの文書に出現するトークンでは、この出現確率が高くなります。
ただし、我々が必要としているのは稀なトークンに高いスコアを与えることです。よって、トークンの出現確率の逆数をスコアの計算で使います。
つまり、多くの文書に出現するトークンでは、出現確率の逆数が小さくなるので低いスコアが割り当てられる、という理解の仕方です。
例えば、コーパスが1000の文書で構成され、「cat」が100文書に登場する場合、出現確率は$${\frac{100}{1000} = 0.1}$$となり、その逆数は10です。
また、「dog」が1文書のみに出現するならば、出現確率は$${\frac{1}{1000} = 0.001}$$となり、その逆数は1000です。
よって、多くの文書に出現するトークンは低いスコアが与えられ一方で、特定の文書に特有のトークンには高いスコアが与えられることになります。
結果としてIDFは、出現確率の逆数に対数を適用したものになります。
TF-IDF の計算
TF-IDFは、TFとIDFを掛け合わせたものです。よって、TF-IDFのことをTF*IDFと表記すること間あります。
なお、Wikipediaによると、TF-IDFの表記として以下があります。
TF-IDF
TF*IDF
TFIDF
Tf–idf
tf–idf
どれが正しい表記なのかを議論する必要はありません。どれが使われても文脈から判断できるようになっていれば問題ありません。
さて、TFとIDFを掛け合わせることにより、他の文書ではあまり見られないが文書内で頻繁に登場するトークンが高いスコアを持つようになります。
$$
\begin{aligned}
\text{TF-IDF} &= \text{TF} \times \text{IDF} \\
&= \text{文書内のトークンの頻度} \times \log \left(\dfrac{文書総数}{トークンを含む文書の数}\right)
\end{aligned}
$$
上述の同じ例を使うと、文書Aで「cat」のTFが0.03、IDFが1であれば、TF-IDFは0.03 * 1 = 0.03となります。
まとめると、TF-IDFは文書内のトークンの重要性(ユニーク度)を計算して文書を評価するための手法です。
TF-IDFの具体例
TF-IDFの具体例を示します。前述した例と同じコーパスを使います。
コーパスの準備
コーパスとして3つの短い文書を使用します。
文書1: 「私は犬が好きです」
文書2: 「私は猫が好きです」
文書3: 「犬と猫は素晴らしい」
コーパスの文書数は3です。
トークン化
各文書をトークンに分割します。
文書1: ["私", "は", "犬", "が", "好き", "です"](トークン6個)
文書2: ["私", "は", "猫", "が", "好き", "です"](トークン6個)
文書3: ["犬", "と", "猫", "は", "素晴らしい"](トークン5個)
TFの計算
各文書内でのトークンの出現頻度を文書内の総トークン数で割ります。
文書1: 私 = 1/6, は = 1/6, 犬 = 1/6, が = 1/6, 好き = 1/6, です = 1/6
文書2: 私 = 1/6, は = 1/6, 猫 = 1/6, が = 1/6, 好き = 1/6, です = 1/6
文書3: 犬 = 1/5, と = 1/5, 猫 = 1/5, は = 1/5, 素晴らしい = 1/5
この例では各文章内のどのトークンも一度しか出現しないので特に興味深い特徴は見られません。強いて言うなら、文章3はトークン数が5個で他の文章よりも少ないので一つのトークンのTFによる重みが比較的に高くなっています。
IDFの計算
次に、各トークンがコーパス全体で何文書に登場するかを数えます。そして、コーパス内の文書数を出現頻度で割り対数を計算します。
私 : 2文書(文書1、2) => $${\log 3/2}$$
は : 3文書(文書1、2、3)=> $${\log 3/3 = 0}$$
犬 : 2文書(文書1、3) => $${\log 3/2}$$
が : 2文書(文書1、2) => $${\log 3/2}$$
好き : 2文書(文書1、2) => $${\log 3/2}$$
です : 2文書(文書1、2) => $${\log 3/2}$$
猫 : 2文書(文書1、2) => $${\log 3/2}$$
と : 1文書(文書3) => $${\log 3/1}$$
素晴らしい: 1文書(文書3) => $${\log 3/1}$$
「は」はどの文章に出現するのでIDFが0になっています。つまり、重要ではありません。反対に「と」や「素晴らしい」は文書を特徴付けるのに重要になります。
TF-IDFの計算
TFとIDFを掛け合わせて各文書の各トークンのTF-IDFスコアを計算します。
文書1:
私 = $${\frac{1}{6} \times \log\left(\frac{3}{2}\right)}$$
は = $${\frac{1}{6} \times 0 = 0}$$
犬 = $${\frac{1}{6} \times \log\left(\frac{3}{2}\right)}$$
が = $${\frac{1}{6} \times \log\left(\frac{3}{2}\right)}$$
好き = $${\frac{1}{6} \times \log\left(\frac{3}{2}\right)}$$
です = $${\frac{1}{6} \times \log\left(\frac{3}{2}\right)}$$
文書2:
私 = $${\frac{1}{6} \times \log\left(\frac{3}{2}\right)}$$
は = $${\frac{1}{6} \times 0 = 0}$$
猫 = $${\frac{1}{6} \times \log\left(\frac{3}{2}\right)}$$
が = $${\frac{1}{6} \times \log\left(\frac{3}{2}\right)}$$
好き = $${\frac{1}{6} \times \log\left(\frac{3}{2}\right)}$$
です = $${\frac{1}{6} \times \log\left(\frac{3}{2}\right)}$$
文書3:
犬 = $${\frac{1}{5} \times \log\left(\frac{3}{2}\right)}$$
と = $${\frac{1}{5} \times \log\left(\frac{3}{1}\right)}$$
猫 = $${\frac{1}{5} \times \log\left(\frac{3}{2}\right)}$$
は = $${\frac{1}{5} \times 0 = 0}$$
素晴らしい = $${\frac{1}{5} \times \log\left(\frac{3}{1}\right)}$$
TF-IDFベクトル
TF-IDFもBoW(Bag of Words)と同様に、各文書を数値ベクトルとして表現します。ただし、TF-IDFベクトルは単純な出現頻度ではなく、各トークンの重要性を反映したスコア(TF-IDFスコア)を持つ点が異なります。
このベクトルはBoWベクトルと同様に各次元がコーパス内のトークンに対応します。
再掲すると、コーパス内の全トークン(語彙)は次のリストです。
語彙:["私", "は", "犬", "が", "好き", "です", "猫", "と", "素晴らしい"]
この語彙リストに基づいた各文書のTF-IDFベクトルは以下になります。
文書1「私は犬が好きです」のTF-IDFベクトル:
$${\left[\frac{1}{6} \log\left(\frac{3}{2}\right), 0, \frac{1}{6} \log\left(\frac{3}{2}\right), \frac{1}{6} \log\left(\frac{3}{2}\right), \frac{1}{6} \log\left(\frac{3}{2}\right), \frac{1}{6} \log\left(\frac{3}{2}\right), 0, 0, 0\right]}$$
文書2「私は猫が好きです」のTF-IDFベクトル:
$${\left[\frac{1}{6} \log\left(\frac{3}{2}\right), 0, 0, \frac{1}{6} \log\left(\frac{3}{2}\right), \frac{1}{6} \log\left(\frac{3}{2}\right), \frac{1}{6} \log\left(\frac{3}{2}\right), \frac{1}{6} \log\left(\frac{3}{2}\right), 0, 0\right]}$$
文書3「犬と猫は素晴らしい」のTF-IDFベクトル:
$${\left[0, 0, \frac{1}{5} \log\left(\frac{3}{2}\right), 0, 0, 0, \frac{1}{5} \log\left(\frac{3}{2}\right), \frac{1}{5} \log\left(\frac{3}{1}\right), \frac{1}{5} \log\left(\frac{3}{1}\right)\right]}$$
TF-IDFで機械学習
TF-IDFベクトルは、BoWベクトルと同様に、各文書を数値ベクトルとして表現します。ただし、TF-IDFベクトルは、各トークンの出現頻度だけでなく、そのトークンが文書全体でどれだけ重要かを反映したスコアを含みます。
したがって、BoWと同じ形式でベクトルが生成されますが、その内容には重要な違いがあり、より精緻な特徴を捉えることができます。
また、BoWと同様に類似度計算やテキストの分類などの機械学習の入力に使われます。
さらに、n-gramを使って連続したトークンの組み合わせに対してもTF-IDFを計算することができます。これにより、単語の順序や文脈情報を部分的に考慮した特徴ベクトルを得ることができます。
トークナイザーの不備
今回紹介したトークン化の手法は、初期の頃によく使われていたものであり、NLTKなどのライブラリで実装され、広く利用されていました。
トークン化のためのツールをトークナイザー(Tokenizer)と呼びますが、初期のトークナイザーにはいくつかの問題がありました。
例えば、ボキャブラリに登録されていない単語の処理が難しいです。するとスペルが正しくない単語に対応できません。しかし、人間は常にスペルを見違えます。それでも意味を読み取ることはできます。
さらに、トークン化の処理が言語ごとに大きく異なるのも問題です。この世界にはたくさんの言語があり、各言語に対して人間が性能の高いトークナイザーを開発・維持することは大変な労力と時間を要します。
しかし、近年に主流になったトークナイザーはこれらの問題を解決し、より柔軟性の高いものへと進化しています。これにより、様々な言語やタスクに対応できるようになり、自然言語処理の適用範囲が大幅に広がりました。
これら発展したトークナイザーの仕組みについても後の記事で紹介し、その特徴や利点について解説する予定です。
次回予告
次回は、トークンをベクトル化する埋め込みについて解説します。
埋め込みベクトルを使うと文章全体の特徴だけでなく、トークン間の関係などを数値として計算することが可能となります。
お楽しみに!
