pythonとWord2Vecで連想語辞書を作成した際の作業記録を残します。コーパスにはWikipediaのDumpを利用させて頂いています。
前提
- OSはAmazonLinux2、形態素解析エンジンのMeCabがインストール済であること。
- ※ MeCabのインストールについては前回または他の方のインストール記事を参考にして下さい。
作業手順
pythonとpip、依存するライブラリのインストール
$ sudo yum install -y python3
$ echo 'alias python=python3.7' >> ~/.bashrc
$ source ~/.bashrc
それぞれバージョンを表示させられればOK。
$ python --version
Python 3.7.10
$ pip3 --version
pip 20.2.2 from /usr/lib/python3.7/site-packages/pip (python 3.7)
ライブラリをインストール。
pip3 install mecab-python3 wikiextractor gensim
コーパスとしてwikipediaのDumpを取得
※ 詳細はWikipedia:データベースダウンロード参照。
wget https://dumps.wikimedia.org/jawiki/latest/jawiki-latest-pages-articles.xml.bz2
取得したデータからModelを生成
wikipediaのDumpはタグなどが含まれておりそのまま自然言語処理に利用するのは難しい。そこでWikiExtractorでクリーニングする。
python -m wikiextractor.WikiExtractor ./jawiki-latest-pages-articles.xml.bz2 --processes 16 -o result/ -b 50m
クリーニングしたテキストデータがresult/以下にwiki_NNの名で生成される。
├── AA
│ ├── wiki_00
│ ├── wiki_01
│ ├── wiki_02
│ ├── wiki_03
(省略)
│ ├── wiki_64
│ └── wiki_65
そこで今度はこれらファイル群にクリーニング・単語分割・正規化・ストップワードの除去をそれぞれかけていく。今回はpythonスクリプトを利用した。
python convert.py
convert.pyの内容は下記の通り。
import re
import os
import MeCab
from multiprocessing import Pool
mecab = MeCab.Tagger ("-d /usr/local/lib/mecab/dic/mecab-ipadic-neologd/ -F\"%f[6] \" -U\"%m \" -E\"\n\"")
def convert(filename: str):
if os.path.exists(filename) == False:
return
isTitleNext = False
with open(filename, mode='rt', encoding='utf-8') as reader:
with open(filename + '.result', mode='w') as writer:
for line in reader:
# クリーニング
if '</doc>' in line:
continue
if '<doc id=' in line:
isTitleNext = True
continue
if isTitleNext == True:
isTitleNext = False
continue
if len(re.sub('[0-9a-zA-Z ]*', '', line)) == 0:
continue
# 単語分割と正規化(※ MeCabを呼ぶときのオプション部分が正規化)
parsedLine = mecab.parse (line)
# ストップワードの除去
parsedLine = parsedLine.strip()
parsedLine = parsedLine.strip(".")
parsedLine = re.sub('[。、,.]', '', parsedLine)
parsedLine = re.sub(' +', ' ', parsedLine)
if (len(parsedLine.split(" ")) <= 2) or (" " in line == False):
continue
writer.write(parsedLine)
filePaths = []
for current, dummy, files in os.walk("./result/"):
for file in files:
filePaths.append(current + "/" + file)
cpuCount = 16
p = Pool(cpuCount)
p.map(convert, filePaths)
p.close()
処理後のテキストデータが[元ファイル名].resultの名でできる。
│ ├── AA
│ │ ├── wiki_00
│ │ ├── wiki_00.result
│ │ ├── wiki_01
│ │ ├── wiki_01.result
(省略)
│ │ ├── wiki_64
│ │ ├── wiki_64.result
│ │ ├── wiki_65
│ │ └── wiki_65.result
そこで結果を統合して1テキストファイルにまとめ、pythonスクリプトを利用してモデルを生成する。
find ./result/ -name *.result | xargs cat >> ./result/all.txt
python createmodel.py
createmodel.pyの内容は下記の通り。
from gensim.models import word2vec
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
sentences = word2vec.Text8Corpus('./result/all.txt')
model = word2vec.Word2Vec(sentences, vector_size=200, min_count=20, window=15, workers=14)
model.wv.save_word2vec_format("./wikiall.vec.pt", binary=True)
wikiall.vec.pt という名のファイルが生成される。後はこれをKeyedVectorsのmost_similar()から利用すれば連想語辞書となるため、スクリプト等から呼び出せばよい。
$ python usemodel.py たま駅長
[('貴志駅', 0.7633522748947144), ('和歌山電鐵', 0.6615394949913025), ('名誉駅長', 0.6613053679466248), ('駅長', 0.6518781185150146), ('芦ノ牧温泉駅', 0.5756949782371521), ('マスコットキャラクター', 0.5370191931724548), ('イメージキャラクター', 0.5328614115715027), ('貴志川線', 0.523949921131134), ('わさお', 0.5135292410850525), ('一日駅長', 0.5096750259399414)]
"たま駅長"の語からちゃんと'貴志駅'、'和歌山電鐵'、'名誉駅長'などの語が導き出せている。
※たま駅長は和歌山電鐵貴志駅の名誉永久駅長。
尚usemodel.pyの内容は下記の通り。
import sys
from gensim.models import KeyedVectors
wv = KeyedVectors.load_word2vec_format('./wikiall.vec.pt', binary=True)
results = wv.most_similar(positive=[sys.argv[1]], topn=10)
print(results)
以上。