テキスト処理総まとめ〜Bag-of-Words, MeCab, CaboCha, TF-IDF,  Word2Vec,  Doc2Vec〜

## 目次
- Bag-of-X
    - Bag-of-Words
    - Bag-of-n-Grams
- 日本語の言語処理（MeCab, CaboCha）
- TF-IDF
- Word2Vec
- Doc2Vec

## 自然言語処理に関連した主な用語集
自然言語処理の分野では特有の専門用語がよく出てくるので、まずそれを抑えます。

##### ストップワード
代名詞、冠詞、前置詞のような、文章の内容によらず一般的に使われる単語のこと。
英語だと例えば、a, about, am, an, been, they, myself・・・など。
日本語だと、「の」、「は」、「です」、「ます」・・・など。


##### ステミング
単語を語幹（単語の語形変化における基礎となる部分のこと）の形に変換する自然言語処理の技術。
例えば、'swimmer', 'swimming', 'swim'のような変化形を同じ単語として認識する。

##### コーパス
自然言語処理の単語で解析対象となる文書全体のことを指す。ほぼテキストデータセットと同じ意味。

##### 分かち書き
単語の意味ごとに空白で区切られたもの。
英語だと例えば、スペース、句読点で区切ればいいが、日本語だと単語同士がつながっているので難しい。
そこで、あとで紹介する主な形態素解析ツールMeCabを使用する。

##### パース処理
テキストデータから本当に解析対象としたい文章のみを文字列として抽出すること。
例えば、Webページの場合HTMLタグを取り除いたり・・・。
データのクリーニング処理。

##### トークン化
英語だと通常、文章中で単語の境界となる区切り文字（delimiter）で分けられたもの。（スペースと句読点）
トークン=単語と考えることもできれば、前述のステミングなどの処理を挟むこともできる。
日本語だと主に後述する形態素解析ツールMeCabを用いる。

##### コロケーション
自然言語処理の分野以外でもたまに聞く用語だが、
ある単語と単語の「よく使われる組み合わせ、自然な語のつながり」のこと。

##### チャンク化
品詞に基づいてトークンの配列を抽出する手法。
日本語だと、文節に分けること。

## Bag-of-Words
Bag-of-Words(BoW)はテキスト文書を単語の出現回数のベクトルで表現したもの。
テキストデータセット中に現れる全ての単語を集めたものを**語彙**(vocabulary)と呼びます。

BoWベクトルは、語彙中の全ての単語に対して、テキスト中にその単語が出現した回数を並べたものです。

以下の図は 'this is an apple' をBag-of-Wordsで表現したものを表しています。

<img width="803" alt="スクリーンショット 2019-04-02 16.24.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/265344/04fea720-330f-2f83-b00b-afb93bcad2d0.png">

- **Bag-of-Wordsのデメリット**

Bag-of-Wordsでは単語の順序は保持されず、テキスト中に単語が何回現れたかだけを記憶します。
しかし、文章を単語に分解することで失われる情報があります。

例えば、'not bad' は 'good' と意味としては同じですが、'not' と 'bad' に分解されることでその意味は失われてしまいます。

以上より、Bag-of−Wordsはシンプルで強力な表現方法ですが、テキストの意味を正しく理解したい場合にはあまり役に立たないでしょう。

次に紹介するBag-of-n-Gramsは、根本的な解決ではありませんが、このような問題を緩和します。

## Bag-of-n-Grams
Bag-of-n-GramsはBag-of-Wordsの自然な拡張です。

nグラムはｎ個の連続したトークンから成る配列です。
単語はnグラムの$n = 1$と考えることができ、**ユニグラム**とも呼ばれます。

nグラムをカウントするとき、トークンの重複を許してカウントを行います。
例えば、先程の 'this is an apple' という文章は、'this is' , 'is an' , 'an apple' という３つのnグラム($n = 2$)を生成します。

nグラムはテキストの順序構造を部分的に保持するが、特徴量の保存やモデリングにかかるコストが増大することに注意が必要です。

## 日本語の言語処理
日本語はトークン同士がつながっているため、英語に比べてトークン化が圧倒的に難しい。
そこで、MeCabとCaboChaという日本語の自然言語処理には欠かせない２つのツールを紹介する。

### MeCab（和布蕪）
MeCabは 京都大学情報学研究科-日本電信電話株式会社コミュニケーション科学基礎研究所 共同研究ユニットプロジェクトを通じて開発されたオープンソース形態素解析エンジンです。C++で書かれています。

形態素解析とは検索エンジンにも用いられている自然言語処理の手法の一つで、ある文章・フレーズを「意味を持つ最小限の単位（＝単語）」に分解することです。

#### Mecabを使ってみる（brewでさくっとインストール）
```shell
$ brew install mecab mecab-ipadic
```

`mecaｂ`というコマンドを叩くと使用することができます。

```shell
$ mecab
今日私は遊園地に行きました。
私	名詞,代名詞,一般,*,*,*,私,ワタシ,ワタシ
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
遊園	名詞,一般,*,*,*,*,遊園,ユウエン,ユーエン
地	名詞,接尾,一般,*,*,*,地,チ,チ
に	助詞,格助詞,一般,*,*,*,に,ニ,ニ
行き	動詞,自立,*,*,五段・カ行促音便,連用形,行く,イキ,イキ
まし	助動詞,*,*,*,特殊・マス,連用形,ます,マシ,マシ
た	助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
。	記号,句点,*,*,*,*,。,。,。
EOS
```

mecabを終了するためには、`Ctrl+C`を入力します。

#### MeCabをPythonから使用する
以下のコマンドでPythonラッパーをインストール。

```shell
$ pip install mecab-python3
```

使い方は以下の様な感じです。

```py
>>> import MeCab as mc
>>> tagger = mc.Tagger('-Ochasen')
>>> print(tagger.parse('今日私は遊園地に行きました。'))
今日	キョウ	今日	名詞-副詞可能
私	ワタシ	私	名詞-代名詞-一般
は	ハ	は	助詞-係助詞
遊園	ユウエン	遊園	名詞-一般
地	チ	地	名詞-接尾-一般
に	ニ	に	助詞-格助詞-一般
行き	イキ	行く	動詞-自立	五段・カ行促音便	連用形
まし	マシ	ます	助動詞	特殊・マス	連用形
た	タ	た	助動詞	特殊・タ	基本形
。	。	。	記号-句点
EOS
```

### CaboCha(南瓜)
CaboChaは、Support Vector Machine(SVM)に基づく日本語係り受け解析器です。

係り受け解析とは、自然言語処理の基礎技術である構文解析です。

CaboChaは文章を形態素に分け、単語間の修飾関係を解析してくれます。

**ex.)** 部屋が蒸し風呂のように暑い。

・形態素解析のみ
　- 部屋
　- 蒸し
　- 風呂
　- 暑い
　　-> 部屋が暑いか特定できない。

・係り受け解析まで
　- 部屋が→蒸し→風呂のように→暑い
　　-> 部屋が暑いか特定できる。





#### CaboChaを使ってみる（brewでさくっとインストール）
まず、CaboChaを利用するためには、crf++が必要なのでインストールします。

```shell
$ brew install crf++
```

cabochaをインストール。

```shell
$ brew install cabocha
```

`cabocha`というコマンドを叩くと使用できます。

```shell
$ cabocha
今日友達とゴルフをした。
    今日-----D
    友達と---D
    ゴルフを-D
        した。
EOS
```

終了するには、`Ctrl+C`を入力します。

#### CabochaをPythonから使用する
gitでGitHubからソースをcloneします。

```shell
$ git clone https://github.com/taku910/cabocha.git
```

Pythonにcabochaをインストールします。

```shell
$ cd cabocha
$ pip install python/
```

使い方は以下の様な感じです。

```py
>>> import CaboCha
>>> cabocha = CaboCha.Parser()
>>> tree = cabocha.parse('今日友達とゴルフをした。')
>>> print(tree.toString(CaboCha.CABOCHA_FORMAT_TREE))
    今日-----D
    友達と---D
    ゴルフを-D
        した。
EOS
```

## TF-IDF
TF-IDFは特徴量スケーリングの一つの方法です。

TF-IDFはTFとIDFの積になります。
TFは単語の**出現頻度**（Term Frequency）、IDFは**逆文書頻度**（Inverse Document Frequency）を意味しています。

TFは、各文章における各単語の出現回数である上述のBag-of-Wordsを正規化して頻度に変えたものです。

IDFはある単語がどれだけ情報をもたらすかを表す量です。
多くの文書に出現する単語の影響は弱くなり、ごく一部の文書に出現する単語の影響が強くなります。

少し数学的に定義を書くと以下のようになります。

$$
bow(w, d) = [文書d内で単語wが出現する回数] \\\
tf(w, d) = bow(w, d) / [文書d単語数] \\\
idf(w) = [全文書数N] / [単語wが含まれる文書数] \\\
ifidf(w, d) = tf(w, d) * idf(w, d)
$$

この逆文書頻度の定義では、ある単語が少数の文書に現れた場合、逆文書頻度は１よりずっと大きくなります。
そこで、IDFは**対数変換**して利用する場合もあります。
対数変換は１を０に変え、１よりもずっと大きな数を小さくします。

## Word2Vec
word2vecは、word embedding手法で、大量のテキストデータを解析し、各単語の意味をベクトル表現化する手法です。単語をベクトル化することで、

- 単語同士の意味の近さを計算
- 単語同士の意味を足したり引いたり

ということが可能になります。

仕組みについては[こちらの記事](https://qiita.com/Hironsan/items/11b388575a058dc8a46a)がとてもわかりやすいです。

Pythonのライブラリgensimを用いることで実装は簡単に行うことができます。

gemsimとは手軽にトピック分析を実行できるライブラリでword2vecも実装されています。

実装はこちらの記事が参考になります！ → [gensimによるword2vecの利用例](https://qiita.com/hsoccer/items/760a2f871c3b3bad1c46)

## Doc2vec
doc2vecは、任意の長さの文書をベクトル化する技術で、文やテキストに対して分散表現（Document Embeddings）を獲得することができます。

特定のタスクに依存することがないので、以下のような様々な応用方法が考えられます。

- コンテンツベースのレコメンド
- 感情分析
- 文書分類
- スパムフィルタリング

さらに、機械学習のモデルにおける入力には固定長のベクトルが使われることが多いので、事前にdoc2vecで前処理をして入力ベクトルにすることも多いです。

例えば、サブスクリプションのビジネスモデルなら、doc2vecで前処理を行い、NNに通すなどして退会予測に使えたり用途はたくさんあると思います。（退会予測は実際に行っています）

そしてこちらも[gemsim](https://radimrehurek.com/gensim/)に実装されているので、実装は比較的簡単に行うことができます。

## 参考記事
https://qiita.com/nezuq/items/f481f07fc0576b38e81d
https://qiita.com/Hironsan/items/11b388575a058dc8a46a
https://qiita.com/hsoccer/items/760a2f871c3b3bad1c46