wikipediaのデータからword2vecコーパスを作成する

# wikipediaのデータからword2vecコーパスを作成する

## GitHub

この記事のコードは全て以下のリポジトリにあります。

https://github.com/tatsuki1119/wiki-word2vec

## 仮想環境の作成

```
conda create -n wikiw2v python=3.10
conda activate wikiw2v
```

## wikiのデータダウンロード

```
curl https://dumps.wikimedia.org/jawiki/latest/jawiki-latest-pages-articles.xml.bz2 -o jawiki-latest-pages-articles.xml.bz2
```

約15分で完了した。

## wikiデータの解凍

`WikiExtractor`で解凍する。

```
pip install git+https://github.com/prokotg/wikiextractor
```

以下コマンドで解凍を実行する。

```
python -m wikiextractor.WikiExtractor jawiki-latest-pages-articles.xml.bz2
```

<details>

  <summary>[出力]</summary>


```
INFO: Preprocessing 'jawiki-latest-pages-articles.xml.bz2' to collect template definitions: this may take some time.
INFO: Preprocessed 100000 pages
INFO: Preprocessed 200000 pages
INFO: Preprocessed 300000 pages
INFO: Preprocessed 400000 pages
INFO: Preprocessed 500000 pages
INFO: Preprocessed 600000 pages
INFO: Preprocessed 700000 pages
INFO: Preprocessed 800000 pages
INFO: Preprocessed 900000 pages
INFO: Preprocessed 1000000 pages
INFO: Preprocessed 1100000 pages
INFO: Preprocessed 1200000 pages
INFO: Preprocessed 1300000 pages
INFO: Preprocessed 1400000 pages
INFO: Preprocessed 1500000 pages
INFO: Preprocessed 1600000 pages
INFO: Preprocessed 1700000 pages
INFO: Preprocessed 1800000 pages
INFO: Preprocessed 1900000 pages
INFO: Preprocessed 2000000 pages
INFO: Preprocessed 2100000 pages
INFO: Preprocessed 2200000 pages
INFO: Preprocessed 2300000 pages
INFO: Preprocessed 2400000 pages
INFO: Preprocessed 2500000 pages
INFO: Preprocessed 2600000 pages
INFO: Preprocessed 2700000 pages
INFO: Loaded 98635 templates in 682.9s
INFO: Starting page extraction from jawiki-latest-pages-articles.xml.bz2.
INFO: Using 11 extract processes.
INFO: Finished 11-process extraction of 2204987 articles in 980.6s (2248.6 art/s)
```

</details>



## Mecabのインストール

https://taku910.github.io/mecab/#win からインストール。
windowsなので、`Binary package for MS-Windows`を選択してダウンロードし、実行すると辞書とともにインストール完了。辞書の文字コードは`UTF-8`を選択した。

このとき、パスが通っていなかったので、環境変数に追加した。

```
pip install mecab-python3
```

Pythonのライブラリもインストールしておく。

## ファイルの結合と分かち書き

解凍されたデータでは、`AA`,`AB`のようにフォルダに分かれて入っているので、フォルダごとに分かち書きをしてテキストを結合し、さらに一つのテキストファイルに結合する。

```python :wiki1_wakati_gather.py
import glob
import logging
import os

import MeCab

if not os.path.exists("./wakati"):  # ディレクトリが無かったら作成
    os.mkdir("wakati")


logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__)

tagger = MeCab.Tagger("-Owakati")

AllData = ''
Folders = glob.glob('text\*')  # textディレクトリ内のフォルダを取得


start_num = 0  # 開始するフォルダの番号を指定
# 一度で実行する場合は0,途中で止まった後に再開するときはその番号

f = open(f"wakati/wiki_data_{Folders[start_num][5:7]}.txt", 'r', encoding='UTF-8')  # 読み込むので"r",UTF-8を指定
AllData = f.read()


for FolderName in Folders[start_num+1:]:
    files = glob.glob(f"{FolderName}\*")  # フォルダの中身を取得
    for file in files:
        f = open(file, 'r', encoding='UTF-8')  # 読み込むので"r",UTF-8を指定
        data = f.read()
        #AllData += data + '\n'
        wakatiData = tagger.parse(data)
        AllData += wakatiData + '\n'
        logger.info(file)
        f.close()

    #wf = open(f'data/wiki_data_{FolderName[5:7]}.txt', 'w', encoding='UTF-8')
    wf = open(f'wakati/wiki_data_{FolderName[5:7]}.txt', 'w', encoding='UTF-8')
    wf.write(AllData)
    wf.close

wf = open('wiki_data.txt', 'w', encoding='UTF-8')
wf.write(AllData)
wf.close()
```

これには２時間程度かかり、途中経過も保存しているためストレージを50GB以上くらい使用するので注意。

途中で止まった場合、`wakati`フォルダ内に途中のデータがあるため、そこから再開できる。その際は`start_num`の値を変更する。

## タグと記号の除去

wikiデータは`<doc></doc>`で囲まれた部分があったり、記号がまだ含まれているのでそれを除去する。

```python :wiki2_remove_tags.py
import re

import MeCab


f = open("wiki_data.txt", 'r', encoding='UTF-8')
data = f.read()
f.close()


# 最初にあるタグを消す
data = re.sub(r"<.*?>", r"", data)
# 半角記号削除
data = re.sub(r'[!"#$%&\'\\\\()*+,-./:;<=>?@[\\]^_`{|}~「」〔〕“”〈〉『』【】＆＊・（）＄＃＠。、？！｀＋￥％]', '', data)
# 全角記号削除
data = re.sub("[\uFF01-\uFF0F\uFF1A-\uFF20\uFF3B-\uFF40\uFF5B-\uFF65\u3000-\u303F]", '', data)

# print(data[0:10000])

#ファイルに書き込み
wf = open('wiki_tag_removed_data.txt', 'w', encoding='UTF-8')
wf.write(data)
wf.close()
```

## 単語のベクトル化

```python :wiki3_make_vector.py
from gensim.models import word2vec
import logging

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
sentences = word2vec.Text8Corpus('./wiki_wakati.txt')

model = word2vec.Word2Vec(sentences, vector_size=200, min_count=20, window=15)
model.wv.save_word2vec_format("./wiki.model", binary=True)
```

これでコーパス（モデル）を作成する。
ここでは200次元、20回以上出現する単語を使用、単語間の最大距離15としている。

## 使ってみる

### 類似単語検索

```python :get_similar_word.py
from gensim.models import KeyedVectors

wv = KeyedVectors.load_word2vec_format('wiki.model', binary=True)
results = wv.most_similar(positive='日本')
for result in results:
  print(result)
```

```
単語を入力
>>> ご飯
('味噌汁', 0.8243885636329651)
('御飯', 0.8029778003692627)
('おかず', 0.7956658005714417)
('炊き込み', 0.7943350672721863)
('汁物', 0.790287435054779)
('チャーハン', 0.7815099358558655)
('おにぎり', 0.7813826203346252)
('米飯', 0.7800269722938538)
('目玉焼き', 0.775774359703064)
('お茶漬け', 0.763556182384491)
```

いい感じ。

### 類似度計算

```python :get_similarity_of_2_words.py
from gensim.models import KeyedVectors

wv = KeyedVectors.load_word2vec_format('wiki.model', binary=True)

jpkr = wv.similarity('日本', '韓国')
print(f'日本と韓国の類似度 : {jpkr}')
```

```
日本と韓国の類似度 : 0.3739430904388428
```

参考：[wikipediaを使ったword2vecコーパスの作り方をまとめてみた](https://qiita.com/Zect/items/d106d46fc94eaa2ed361)