自然言語処理の基本に関するまとめ

※2020年に発表されたGPT-3や2023年に発表されたGPT-4のようなLLM(大規模言語モデル)に関する説明は現在含まれていません。
LLMより前の自然言語処理の内容をまとめているためご注意ください。

# はじめに
最近、自然言語処理始めました。
自然言語処理の分野自体、研究中ということもあり、日々情報が更新されたり、各ワードの関係性が全く分からなかったため、文章分類を軸に一通りの流れや関連するワードをまとめました。
間違った理解をしている場合は、ご指摘ください。
内容は時間が取れれば随時更新を行っています。

以下の悩みを抱えている人に役立つかと思います。

- 自然言語処理と機械学習を使って何かしたいけれども、一連の流れがわからない
- 各ワードは知っているけれども、どのように関連しているのかがわからない
- 流れは大体わかるけれども、具体的に何を使って何をすればよいかわからない

個々のワードで詳しく説明している記事は沢山存在するため、詳細はそちらを参考にしてください。
また、単語のベクトル表現あたり自分の知識がかなり乏しいので、個人的に学習は行いますが、ご自身で調べていただけるとありがたいです。

# 記事の見方
かなり長文の記事になっています。
自然言語処理の基本的な分部に関しては、目次の以下を参照してください。

- 自然言語とは
- 自然言語処理とは
- 自然言語処理の活用
- 自然言語処理の基本的な流れ
- 自然言語のベクトル化

ベクトル化の部分で大まかな流れと関連するキーワードを紹介しています。
気になるキーワードがあれば、ネットで検索したり、当記事の詳細部分を確認して頂けるとよいと思います。

# 自然言語とは
英語や日本語の様に人間が自然発生的に使用してきた言語の事を自然言語といいます。
これに対し、プログラミング言語のような人工言語は形式言語と呼んで区別されます。
`自然言語 <-> 形式言語`

# 自然言語処理とは
自然言語を計算機(コンピューター)で処理する事を指します。
計算機で処理を行う場合、言葉を計算機が計算しやすい様に、数値に変換する必要があります。
画像や音声の場合は、ピクセル数や音の高さ等で表現(数値化)することができます。
それに対して、自然言語の場合は、目的によって最適な表現方法(数値化)が異なる為、数値化が難しいとされています。
簡単な方法としては、単語をあるなし(1, 0)で数値化する方法があります。
これでは、単語ごとの意味が加味されていませんので、現在は、単語や文章の特徴を数値化して計算機で計算を行うことが主流となっています。
具体的な特徴として、文章に出現する単語の頻出頻度や近年は単語同士の関連性が使用されており、また、特徴量の算出方法(アルゴリズム)も複数存在し、目的によって最適な方法が複数取られています。

そのため、どの方法が最適解か決まっておらず、未だに研究中の分野であるとされています。
とはいえ、最近のトレンドを追いかけていると、BERTを中心とした深層学習を使用した学習済みモデルによる単語の数値化(ベクトル化)が精度が良く、頻出度による数値化はあまり精度が出ない印象です。
目的(解きたいタスク)によってBERTがいいか悪いかはありますが、平均的に精度がいいのは深層学習を使用したものが安定して精度を出せる印象です。
その反面、マシンスペックが要求され、文章(単語)の数値化に時間がかかっている印象です。
# 自然言語処理の活用
自然言語処理と機械学習を組み合わせることで、一例として以下のような事(用語としてはタスクといいます)がこなせます。

- 文章分類
- 自動要約
- 機械翻訳
- 文章生成
- 著者推定

ここでは、文章分類を軸に、大まかな流れと、ちょっとした詳細に関して紹介を行います。

# 自然言語処理の基本的な流れ
自然言語を計算機で処理する際の基本的な流れは以下のようなものです。
ここでは、日本語に対しての処理の流れを説明します。

1. 形態素解析
 - 形態素解析器を使用して文を最小単位に分割する。また、各単語を品詞区分に紐付ける。
     - 今日はいい天気 -> "今日", "は", "いい", "天気" 
     - "今日": 名詞, "は": 助詞, "いい": 形容詞, "天気":名詞
3. 構文解析
   - 形態素解析を行った単語同士の関係性を解析する
   - 詳細([自然言語（日本語）処理](http://www.sist.ac.jp/~kanakubo/research/natural_language_processing.html))
5. 意味解析
   - 構文解析をした結果、複数の候補がある場合、意味が伝わる構文を選択する
   - 詳細([自然言語（日本語）処理](http://www.sist.ac.jp/~kanakubo/research/natural_language_processing.html))
7. 文脈解析
   - 複数の文章にまたがる構文解析+意味解析を行う

詳細に関しては、リンク先のページを確認いただいた方がわかりやすいです。
近年は、(特に英語ですが)形態素解析を行い、その単語をベクトル化(数値化)するだけで様々なタスクでよい精度が出ています。
構文解析や意味解析、文脈解析はするに越して事はないかもしれませんが、現状具体的な処理方法が確立されておらず、初心者の方は意識しなくてもよいと思います。
実際のところ、構文解析や意味解析、文脈解析は、深層学習を用いて精度を劇的に上げたWord2Vecが、単語間の意味を加味したベクトル化をしているので、前処理の部分で気にする必要はありません。

# 自然言語のベクトル化
自然言語を計算機に入力するために、言葉を数値化(ベクトル化)する必要があります。

先ほども記述しましたが、現状、形態素解析以降の解析は技術として確立されていないため形態素解析されたデータをベクトル化する事が主流です。

ここでは、自然言語を形態素解析し、ベクトル化して処理する流れを紹介します。
--------------------------①前処理-------------------------------
文章に含まれる不要な単語を削除します。

1. クリーニング処理
   - 不要なタグを削除する
     - HTMLのタグ("\<p\>")など 
2. 形態素解析
   - 形態素解析器を使用して文を最小単位に分割する
     - 今日はいい天気 -> "今日", "は", "いい", "天気" 
   - 解析ツール
      - MeCab
      - Juman ++
      - Janome
   - 形態素解析で使用する辞書
     - UniDic
     - IPADIC
     - NEologd
3. 単語の正規化
   -  同じ意味の単語を統一する
      -  Apple と apple -> どちらもappleに
      -  GCP と Google Cloud Platform -> どちらもGoogle Cloud Platformに
4. ストップワードの除去
   -  自然言語処理に役立たないと思われるワードの削除
      -  そこ、あれ、これ 等

1, 2以外の処理は、ベクトル化を行う際に使用する仕様するライブラリで勝手に処理をしてくれることが多いです。
2の処理は日本語特有の処理となる為、単語で区切られている英語の場合は不要です。

自然言語処理に関わらず、機械学習やデータサイエンスでは、元データを分析/学習しやすい状態にする作業、データの前処理と呼びます。

--------------------------②ベクトル化-------------------------------
文章から単語を分割し、不要な文章を除去したものを使用して、数値化(ベクトル化)を行います。

1. 単語のベクトル表現(数値化)
   - 単語をベクトルに変換する方法
      - One hot表現(Bag Of Words)
         - TF-IDF
         - LSA
         - LDA
      - 分散表現
         - Word2vec
         - Glove
         - FastText
         - BERT
         - T5
         - GPT 等
1. 応用処理
   - 自然言語を数値化したので、機械学習等を活用してタスクをこなす
     - 例)分類器にベクトル化したデータを投入し、文章を分類する
   - ツール(ライブラリ)
     - scikit-learn
     - TensorFlow
     - Keras
     - PyTorch
     - Hugging Face
   - アルゴリズム
     - ナイーブベイズ分類器
     - サポートベクターマシーン(SVM)
     - ランダムフォレスト
     - ロジスティック回帰
     - 勾配ブースティング木
     - ニューラルネットワーク(NN)
     - ディープニューラルネットワーク(DNN, 深層学習)
     - fine-tuning
        - BERT等の深層学習モデルに新たに分類層などを追加する

# 前処理の詳細
## 1. クリーニング処理
Web上からテキストデータをスクレイピング等で取得した場合、余計なHTMLタグが含まれている場合があります。
生の文章データが欲しいため、データの処理には関係ない分部は、テキストデータから除去します。
例) \<p\> 今日は\<b\>本当に\</b\>良い一日でした! \</p\>
     -> 今日は本当に良い一日でした!

正規表現などを活用して、効率的にワードの除去を行います。

## 2. 形態素解析
余分な文字を取り除き、生の文章になったところで、形態素解析を行い文章を単語に分割します。
英語の場合は、すでにスペースで単語が分割されている為、分割処理は不要です。
 
形態素解析は、以下のようなツール(形態素解析器)の利用が主流です。

- MeCab
- JUMAN ++
- Janome
- Sudachi

ツールによって特徴はありますが、簡単に使用するのであれば、大きな違いは無いと思います。
一番利用されているツールはMeCabですので、迷ったらこれを使用するのが良いと思います。
 
また、各形態素解析器は、専用の辞書を元に文章を単語に分割しています。
辞書に関しても特徴があるので、精度が上手く出ないときは気にしてみると良いと思います。

- UniDic
   - かなり細かく単語分けされる
   - 一部直感的でない分割がある -> /寿司屋/ と /家具/屋/
- IPADIC
   - MeCabに標準で利用されている
   - 単語の長さはほどほど
- NEologd
   - Webから語彙を収集するため、最新言語に強い
   - IPADIC、UniDic版があり、それぞれの補完を行う

UniDicやIPADICは、新しい単語に対応していない事が多いです。
例えば、"クラウド"なんかは"クラ/ウド"で分割されるようなことがあります。
それに対して、NEologdに関しては、システムが自動で辞書をアップデートするので、最新の単語にも強い傾向があります。

また、昔からある言葉でも、形態素解析器や辞書によってどの様に分割されるかは異なります。
例) 自然言語処理
自然/言語/処理
自然言語/処理
自然言語処理

この辺りは、実際に試してみないと何とも言えないので、一度形態素解析をした文がどのくらい細かく分割されたのか確認した方が良いでしょう。

形態素解析を行うと、単語ごとにどの品詞のラベルが付きます。
機械学習を使用する際は、どの品詞を学習データに使用するか決める必要がありますので、色々と試してみるとよいでしょう。

## 3.単語の正規化
正規化は主に以下のような作業を行います。

- 大文字/小文字、半角/全角の統一
- 数値の置き換え
- 単語の統一

### 大文字/小文字、半角/全角の統一
以下のような単語は同じ意味を持つ単語ですが、計算機には別の単語だと解釈されてしまいます。
Amazon と amazon
パソコン と ﾊﾟｿｺﾝ
そのため、英語は全て小文字にする、カタカナは全て全角にするなど、単語をどちらかに統一する必要があります。

### 数値の置き換え
文章分類など、分類をする際に数値が意味を持たない場合は、数値を全て同じものに変換する方法があります。
単語はそれぞれがベクトル化され、数値を持つため、影響のない単語は全て統一して1つのベクトルとすることで、機械学習を行う際に数値(次元)が多すぎて学習時間が長くなることや、数値(次元)が多く学習が上手くいかない次元の呪いにかかってしまうことを防ぎます。

例えば、ニュース記事をスポーツとファッションに分類する際、出てくる数値に大きな意味はなさそうなので、数値を全て0に置き換えます。
before: 2019年10月1日、日本は10-0でAAに勝ちました
after: 0年0月0日、日本は0-0でAAに勝ちました

### 単語の統一
英語表記とカタカナ表記を統一したり、略語に関しても、統一を行う必要があります。
Microsoftとマイクロソフト
GCPとGoogle Cloud Platform

## 4.ストップワードの除去
自然言語処理や機械学習を行う際に必要になさそうなワードの除去を行います。
日本語で言えば、以下のようなことばが当てはまるかと思います。
`これ、それ、あれ 等`
英語だと
`it, a this etc...`
ですね。

除去の方法はいくつか存在します。

- 辞書による除外
- 頻出度による除外

### 辞書による除外
予め必要なさそうな単語をまとめた辞書というものが存在します。
一番有名なものだと、`SlothLibプロジェクト`が提供しているワードがあります。
実際に利用したことがないので、何とも言えませんが、テキストファイルで提供されているので、自然言語処理を行うライブラリに取り込ませて不要な単語を除外する流れになると思います。

### 頻出度による除外
文章の中によく出現する単語は文章に影響を与えないといった考えを元にした除外方法です。
例えば、私の文章だと
`に、も、は、しかし、します 等`
が多く出現しているので、私が作成した記事を分類する際には意味がなさそうです。

自然言語処理のライブラリを使用すると、頻出の閾値を自身で指定し、除外することができます。
なので、頻出しすぎる単語を除外するのと同時に、まったく出現しない(1つの文章に固有の単語)も除外することができます。
除外することで、機械学習における学習時間短縮や次元の呪いをさけたり、次元削減がしやすくなると思うので、色々と閾値を変更し、試してみるとよいと思います。

## 5.単語のベクトル表現
文章を単語に分割し、単語の統一や不要な単語を除外できたので、単語を計算機(PC)に計算させる為、単語の特徴量をベクトル(数値)に変換します。
(意味のある計算ができる様に特徴量を算出して数値化します。)
変換方法は大きく分けて二つあります。

- Bag Of Words(BoW)
- 分散表現

現在では、分散表現を行った方が様々なタスクでよい結果が出ています。
(ただ、論文上の結果であるため、実務で使用する際は期待通りの結果が出ないとの話も一部あるようです。)
分散表現を行うためには、大量のコーパス(文章群)が必要になりますが、すでに学習済みのモデルが用意されているので、そちらを利用するのがよいと思います。

### Bag Of Words(BoW)
文章の中に単語がいくつ入っているかをカウントする方法です。
大きなバッグの中に分割した単語を入れてカウントするため、この様な名前がつけられました。
この場合、文章内の単語数に注目するため、文章内における単語の前後関係は考慮されません。

単語を分割し、OneHot表現にするものが簡単で有名です。
文章に出現する単語を、0(なし)と1(あり)の数値で表現します。
数値化のルールとして、単語リストの中である要素のみが1となり、それ以外は全て0にする必要があります。
例)
文章 今日はいい天気です

単語分割
文章 -> 今日 / は / いい / 天気 / です

```
# 出現単語
["今日", "は", "いい", "天気", "です"]

# OneHot表現
[
  [1, 0, 0, 0, 0], <- 1単語目のリスト(今日)
  [0, 1, 0, 0, 0], <- 2単語目のリスト(は)
  [0, 0, 1, 0, 0], <- 3単語目のリスト(いい)
  [0, 0, 0, 1, 0], <- 4単語目のリスト(天気)
  [0, 0, 0, 0, 1] <-  5単語目のリスト(です)
]
```

出現単語リストは[今日, は, いい, 天気, です]となっています。
例文の1つ目の単語は、"今日"が入っているので、最初のリスト([0][0])は[1, 0, 0, 0, 0]となります。

これだけでは、大きな意味を持たないので、以下のような作業を追加で行うことが多いです。

- TF-IDF
- LSI
- LDA

理論までは説明できませんが、簡単に説明します。

### TF-IDF
文章分類を行う際によく利用されます。
Term Frequency(単語の頻出度) - Inverse Document Frequency(逆文書頻出度)の略です。
文章においてその単語がどれくらい出現したのか(単語の頻出度)を計算し、その後に単語のレア度(逆文書頻出度)を算出してベクトル化する方法です。
色々な文章に出てくる単語はレア度が低く、重要でないといった判断をするものです。

### LSI
BoWにおいて、主成分分析(次元削減を行う分析方法)を行って単語行または単語列を少なくする方法です。
複数次元あったものを2次元まで圧縮し、グラフにプロットすることで単語同士の関連度合いを可視化する際になどに利用します。

### LDA
文章をトピックに分ける際に利用します。
文章の潜在的なトピックを予想し、クラスタリングするイメージです。

## 分散表現
One hot表現には、例を見てもわかる通り、長文になるとリストの長さが膨大になる点と、未知の単語に対応できないといった欠点があります。

そこで、近年では分散表現というものが注目されています。
考え方としては、各単語に関して特徴量を200～300個ほど用意するといったものです。

|単語    |大きさ|色|形|...|
|:----:|:-----:|:-:|:-:|:-:|
|車       |0.8|0.1|0.5|...|
|飛行機|0.9|.07|0.7|...|
|自転車|0.4|0.1|0.8|...|

特徴量はイメージです。
単語が増えても、特徴量(次元)は増えず、単語の数が増えるだけなので、One hot表現の様にリストの長さ(次元)が膨大に増えるといった点が解消されます。

分散表現を行う方法としては、以下の方法が有名です。

- Word2vec
- Glove
- FastText
- BERT
- T5
- GPT

まだ完全に理解していないため、触り程度で紹介します。

### Wrd2Vec
Googleの研究者が提案した分散表現を行うニューラルネットワークです。
事前に大量のテキストを学習し、単語同士の意味の近さを計算したり、単語の足し引きがが可能になります。
`"王様" - "男" + "女" = "女王"`といった計算ができるといった話が有名ですね。

### Glove
Word2vecの様に分散表現を行うことができる方法です。
Word2vecは、事前に学習をする際に非常に時間がかかりますが、高速にかつ高性能で分散表現ができる方法として有名です。

### FastText
Facebookが開発した手法です。
Word2vecよりも後に開発された為、高速で未知の単語にも対応している等Word2vecでの課題を解決しているようです。

### BERT
今最も注目されている手法です。
Googleが開発しました。
今までは、自然言語処理の色々なタスクに関して、良い精度を出すためには、それぞれに会った手法をとる必要がありましたが、BERTは複数のタスクに関して高い精度が出たということで注目されています。
取りあえずBERTで学習させたものを色々なタスクに使用できるということです。
[BERTとは何か？Googleが誇る最先端技術の仕組みを解…｜Udemy メディア](https://udemy.benesse.co.jp/ai/bert.html)

### 分散表現の実施(実装)方法
このような手法は次のようなライブラリ経由で使用することが主流です。

- TensorFlow
- Keras
- PyTorch
- Hugging Face

これらのライブラリは、次の応用処理も一緒に処理する機能を持ち合わせている為、一気に応用処理をしてもよいですし、ベクトル化だけ行い、応用処理は次に紹介するライブラリを使用して行うといった方法も取ることがあります。

## 6.応用処理
文章を単語に分割し、計算機が読み込めるように数値化(単語のベクトル表現)ができたので、そのベクトルを使用して、処理を行います。

ここでは、文章分類に関して簡単に説明します。
### 文章分類
ニュース記事をカテゴリに分類することをイメージしてください。
各記事に正解ラベルを付け加えて、記事を単語ベクトル化し、機械学習を行ってモデルを作成します。
そのモデルを使用して、新しい記事を単語ベクトル化したものを入力して、どのカテゴリに属する記事なのかを予測します。

機械学習の部分では、以下のようなアルゴリズムが使用されます。

- ナイーブベイズ分類器
- サポートベクターマシーン(SVM)
- ランダムフォレスト
- ロジスティック回帰
- 勾配ブースティング木
- ニューラルネットワーク(NN)
- ディープニューラルネットワーク(DNN, 深層学習)

よく文章分類に利用されるのは、ナイーブベイズ分類器でしょうか。
学習や分類速度が他と比べ圧倒的に早く、教師データが少なくても分類できるのが特徴です。
SVMは昔からある手法ですが、精度がよい印象です。ただし、ナイーブベイズ分類器と比較すると学習速度が遅いのが難点です。
ニューラルネットワーク系に関しては、学習速度がかなり遅いです。特にディープニューラルネットワークの場合、学習データがかなり必要(数千とか)ですので、上手くいけば精度が出るかもしれませんが、少ないデータ量で学習をさせる際は、ナイーブベイズ分類器やSVMがおすすめです。

上記のアルゴリズムは、以下のツールを使用すると簡単に利用することができます。

- scikit-learn

他にもツールは存在しますが、scikit-learnには様々な機能が備わっている為、少し試したい場合に使用するのはよいと思います。
(*ディープニューラルネットワークは実装されていません)
また、TF-IDFを行う機能も備わっているので、一通りの事は可能かと思います。

使い方に関しては、他のサイトを参考にしてみてください。
アルゴリズムは以下のページに一覧化されているので、分類を意味する"Classifier"と書いてあるものを使用すると分類ができます。
[API Reference — scikit-learn 0.21.3 documentation](https://scikit-learn.org/stable/modules/classes.html)

# 最後に
最後までお付き合いありがとうございました。
自身の自然言語処理に対する理解が薄いと思い立ってすぐに作成した記事なので、読みにくい部分等あるかもしれません。
何かアドバイス等ありましたら、お気軽にコメントをください。