Word2Vecで深層学習をやってみた

# Wikipedia全文データを利用した深層学習
2020/9/18 投稿
## 概要

### 動機
大学の講義でせっかく深層学習をお勉強したので、自分の中だけにとどめておくのも勿体ないと思い、書かせていただきます。
レポートを少し崩した感じで書かせていただきますが、一部間違いなどもあると思いますのでご了承ください。

### 環境
MacBookPro macOS 10.14.6 ->PC
Python 3.7.5rc1 -> プログラミング言語
Mecab (0.996) -> 形態素解析器
Visual Studio Code -> 開発環境
### 内容
1. Wikipediaの全文データをダウンロード
2. データを整形(URLやHTMLタグを取り除く)
3. 形態素解析
4. 分かち書きファイルの作成
5. 文書検索

## 目的
- Pythonの基本のお勉強
- 単位を取るｗ
- 深層学習*自然言語処理の基礎のお勉強

##手順
### 1.wikipediaから全文データをダウンロードします。


[参考：日本語のWikipediaの全文データを使ってWord2vecを訓練する](https://qiita.com/hiroshijsc16/items/183dd3d5b6c31b587523)

ダウンロードには１時間程度かかってしまいます。テキストデータですが、なにせ全文データなのでダウンロードに１時間以上はかかりました。

### 2.圧縮ファイル解凍
.bz2形式に圧縮されていたため、解凍を行い,xml形式のデータを得ます。

### 3.xml -> txt への変換
xmlからtxtファイルへ変換する。
wp2txtをインストールする。

```terminal
pip install wp2txt
```

そして、実行する。


```terminal
wp2txt --input-file ./jawiki-katest-pages-article.xml
```

(cd コマンドでwikipediaのxmlファイルのある位置を指定していおく)
1ファイルあたり、10MBくらいのtxtファイルを得ることができた。

4. 文書の前処理
3で作成したtxtファイルはHTMLタグやURL、()などがあるため取り除く。
-> これらは言語を解析する上で邪魔(ノイズ)になる。

正規化表現で取り除きます。

```python

            s = line
            s = re.sub(r'==.+?==', '', s)
            s = re.sub(r'\{\{.+?\}\}', '', s) 
            s = re.sub(r'\*\S+?', '', s) 
            s=re.sub(r'(https?|ftp)(:\/\/[-_\.!~*\'()a-zA-Z0-9;\/?:\@&=\+$,%#]+)','',s)
            s=re.sub(r'<.+?>.+?</.+?>','',s)
            s=re.sub(r'[!\"#$%&\'()\*\+\-\.,\/:;<=>?@\[\\\]^_`{|}~（）｢｣「」【】『』、。・–]+','',s)
            s=re.sub(r'<#.+?','',s)

```

上記含め、プログラムの全体像

```python

import MeCab
import re
from joblib import Parallel, delayed
def mainproc(n): n=n+1
with open("/Volumes/WD_Elements/wp2txt/jawiki-latest-pages-articles- "+"{:0=3}".format(n)+".txt", "r", encoding="utf-8")as fobj:
for line in fobj:
MECAB_MODE = 'mecabrc'
tagger = MeCab.Tagger(MECAB_MODE) tagger.parse("")
s = line
s = re.sub(r'==.+?==', '', s)
s = re.sub(r'¥{¥{.+?¥}¥}', '', s)
s = re.sub(r'¥*¥S+?', '', s) s=re.sub(r'(https?|ftp)(:¥/¥/[-_¥.!~*¥'()a-zA-Z0-
9;¥/?:¥@&=¥+$,%#]+)','',s) s=re.sub(r'<.+?>.+?</.+?>','',s)
s=re.sub(r'[!¥"#$%&¥'()¥*¥+¥-¥.,¥/:;<=>?@¥[¥¥¥]^_`{|}~()「」「」【】『』、。・ –]+','',s)
s=re.sub(r'<#.+?','',s) node = tagger.parseToNode(s)
          words = []
          while node:
pos = node.feature.split(",")[0] word = node.surface
if pos =='名詞'or'形容詞'or'動詞':
words.append(word) node = node.next
#print(words) # --- 画面に分かち書きした行を表示
wakati_file = "/Volumes/WD_Elements/100/corpus{:0=3}".format(n)+".wakati"
with open(wakati_file, 'a', encoding='utf-8') as fp: fp.write(' '.join(words))
print("{:0=3}の処理終了".format(n)) 
sub=Parallel(n_jobs=-1)([delayed(mainproc)(i) for i in range(5)])
import MeCab
import re
from joblib import Parallel, delayed

def mainproc(n):
    n=n+1
    with open("/Volumes/WD_Elements/wp2txt/jawiki-latest-pages-articles-"+"{:0=3}".format(n)+".txt", "r", encoding="utf-8")as fobj:
        for line in fobj:
            MECAB_MODE = 'mecabrc'
            tagger = MeCab.Tagger(MECAB_MODE)
            tagger.parse("")
            s = line
            s = re.sub(r'==.+?==', '', s)
            s = re.sub(r'\{\{.+?\}\}', '', s) 
            s = re.sub(r'\*\S+?', '', s) 
            s=re.sub(r'(https?|ftp)(:\/\/[-_\.!~*\'()a-zA-Z0-9;\/?:\@&=\+$,%#]+)','',s)
            s=re.sub(r'<.+?>.+?</.+?>','',s)
            s=re.sub(r'[!\"#$%&\'()\*\+\-\.,\/:;<=>?@\[\\\]^_`{|}~（）｢｣「」【】『』、。・–]+','',s)
            s=re.sub(r'<#.+?','',s)
            node = tagger.parseToNode(s)

            words = []
            while node:
                    pos = node.feature.split(",")[0]
                    word = node.surface
                    if pos =='名詞'or'形容詞'or'動詞':
                        words.append(word)

                    node = node.next

            #print(words) # --- 画面に分かち書きした行を表示
            wakati_file = "/Volumes/WD_Elements/100/corpus{:0=3}".format(n)+".wakati"
            with open(wakati_file, 'a', encoding='utf-8') as fp:
                fp.write(' '.join(words))
    print("{:0=3}の処理終了".format(n))

sub=Parallel(n_jobs=-1)([delayed(mainproc)(i) for i in range(5)])

```

### 5.分かち書きファイルの作成
#### 分かち書きとは？
> 文を書く時、ある単位ごとに区切って、その間に空白を置くこと。また、その書き方。「たかいやまへのぼる」の類。単語ごとに分ける、文節ごとに分ける、両者を折衷するなどがある。分別書き方。

[参考：コトバンク](https://kotobank.jp/word/%E5%88%86%E3%81%8B%E3%81%A1%E6%9B%B8%E3%81%8D-415124)

今回は、名詞、形容詞、動詞に一致するものを抽出の対象としました。
助詞や助動詞などは、それ自体に意味を持つことは少ないので除去します。

￥この辺の処理は、目的によって工夫する必要があります。｢…だが,***ではない｣という文がある場合、… が***と類似しているという判定になってしまうこともあります。

### 6.modelファイルの作成
Word2Vecによって深層学習をおこなう。

Word2Vecとは？
> Word2Vecとは、当時Googleに在籍していた研究者であるトマス・ミコロフ氏らにより提案され、自然言語処理に大きな技術的進展をもたらしたツールです。それまでの自然言語処理手法が抱えていたさまざまな課題を乗り越え、大規模データによる自然言語処理学習を可能にし、Googleのみならずさまざまな企業でも活用が始まっています。

[Word2Vecとは | 分散表現・Skip-gram法とCBOWの仕組み・ツールや活用事例まで徹底解説](https://ledge.ai/word2vec/)

```python
# Word2Vecでモデルを作成 --- (※6)
from gensim.models import word2vec
wakati_file = "/Volumes/WD_Elements/検索技術作業用/models/corpus1.wakati"
data = word2vec.LineSentence(wakati_file)

#1
model = word2vec.Word2Vec(data,size=200, window=10, hs=1, min_count=2, sg=1)
model.save('/Volumes/WD_Elements/models/corpus1.model')
print('\n\n\n\n\n ------------------------------------ok\n')
```

### 7.文書群の解析
modelファイルを使って、入力文字に対して近い単語を表示させます。
尚、入力文字が辞書上(学習モデル上)になければエラーが吐き出されます。

```python

from gensim.models import word2vec
print("model_num?")
n=input()
print("Loading")
model = word2vec.Word2Vec.load('/Volumes/WD_Elements/models/corpus'+str(n)+'.model')
m=1
print("準備完了(終了はexitを入力)")

while 0<m:
    str=input()
    if str=="exit":
        break
    try:
        for word in [str]:
            words = model.most_similar(positive=[word])
            n = [w[0] for w in words]
            print("SimilarWord\n")
            print(word,"=", ",".join(n))

    except:
        print("\n\nボキャブラリーがありません\n\n")

```

## 感想
結構前にやったやつだから忘れてしまってる部分も多いです…。
数学的に考えるとかなり難しいアルゴリズムであるのは間違いないようです。しかし、その辺まで勉強するには至りませんでした。

実務レベルだとどういう応用がされているかはわかりませんが、今回は数学的にモデルを解釈するのではなく、やってみることに重点をおいたので、深層学習がざっとこんなものかというのは理解することができました。