はじめに
次の記事
nora(野良)-idf-dic
を参考にさせていただき、EC2(CentOS)で、WikiepdiaダンプファイルからMeCabによって単語のidf値をJsonファイルに出力させました。
EC2(CentOS)でMeCabを使えるようにする
作業用ディレクトリ作成
mkdir ~/mytmp
python3.7インストール
sudo yum install python37 –y
git、gcc、g++、cmakeインストール
sudo yum install -y git
sudo yum install gcc gcc-c++
cd ~/mytmp
wget https://cmake.org/files/v3.12/cmake-3.12.3.tar.gz
tar zxvf cmake-3.12.3.tar.gz
cd cmake-3.12.3/
sudo ./bootstrap
sudo make
sudo make install
MeCabインストール
cd ~/mytmp
wget 'https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7cENtOXlicTFaRUE' -O mecab-0.996.tar.gz
tar zxvf mecab-0.996.tar.gz
cd mecab-0.996
sudo mkdir -p /usr/bin/mecab
sudo ./configure --prefix=/usr/bin/mecab --with-charset=utf8 --enable-utf8-only
echo "export PATH=/usr/bin/mecab/bin:\$PATH" >> ~/.bashrc
sudo make
sudo make install
source ~/.bashrc
mecab-config --libs-only-L | sudo tee /etc/ld.so.conf.d/mecab.conf
sudo ldconfig
MeCabインストール先確認
which mecab
(/usr/bin/mecab/bin/mecab)
mecab-python3インストール
pip3 install mecab-python3
leveldb(Googleが作った高速なkey-valueDB)、plyvelインストール
pip install plyvel
cd ~/mytmp
git clone https://github.com/google/leveldb.git
cd leveldb
mkdir -p build && cd build
cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .
Neologd(MeCab 用辞書)インストール
git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
cd mecab-ipadic-neologd
./mecab-ipadic-neologd/bin/install-mecab-ipadic-neologd -n -y
Neologdインストール先確認
echo `mecab-config --dicdir`"/mecab-ipadic-neologd"
(/usr/bin/mecab/lib/mecab/dic/mecab-ipadic-neologd)
テスト
echo "私は学生です。" | mecab -d /usr/bin/mecab/lib/mecab/dic/mecab-ipadic-neologd
IDF計算プログラム
###分かち書きデータの保存###
Wikipediaダンプデータの各記事の分かち書きを、LevelDBへの保存します。
分かち書きはMeCabを使い、正規化のために単語の原型を採用しています。
# coding: utf-8
from __future__ import print_function
import os
import sys
import re
import xml.etree.ElementTree as et
import MeCab
from collections import Counter
import json
import math
import pickle
import plyvel
import time
import unicodedata
def _my_wakati_split(mecab,text):
parsed_split = []
node = mecab.parseToNode(text)
while node:
word = node.surface
genkei = node.feature.split(",")[6]#正規語句
if(genkei == '*'):#正規語句がない場合
genkei = word
if(genkei):
genkei = unicodedata.normalize('NFKC', genkei)#英数字記号半角・カタカナ全角
genkei = genkei.lower()#小文字英字
parsed_split.append(genkei)
node = node.next
return parsed_split
start = time.time()
db = plyvel.DB('title_context.ldb', create_if_missing=True)
mecab = MeCab.Tagger ("-Owakati -d /usr/bin/mecab/lib/mecab/dic/mecab-ipadic-neologd")
cursol = None#記事タイトル
count = 0#記事のカウント
for i, (event, elem) in enumerate(et.iterparse('./jawiki-20230220-pages-articles.xml')):
if count%2500 == 0:
print("now docs %d"%count)
print(cursol)
if 'title' in elem.tag:
cursol = elem.text.replace('\n', '')
continue
if 'text' in elem.tag:
count += 1
if db.get(bytes(cursol, 'utf-8')) is not None:
continue
if elem.text == None:
continue
text = elem.text.replace('\n', '')
for remove in [re.compile(x, re.MULTILINE) for x in [r'\(.*\)', r'\[\[', r'\]\]', r'<.*?>', r'\[.*?\]', r'{{.*?}}']]:
text = re.sub(remove, '', text)
parsed_split = _my_wakati_split(mecab,text)
if len(parsed_split) == 0:
continue
cursol = unicodedata.normalize('NFKC', cursol)
cursol = cursol.lower()
db.put(bytes(cursol, 'utf-8'), pickle.dumps(parsed_split) )
#if count == 2500:#テスト用
# break
elem.clear()
print("total len=%d"%i)
end = time.time() - start
print(f"処理時間:{end}")
###IDF値Jsonファイルの作成###
LevelDBに保存された分かち書きデータから、全単語のidf値を計算して、Jsonファイルに保存します。
# coding: utf-8
from __future__ import print_function
import os
import sys
import re
import xml.etree.ElementTree as et
import MeCab
from collections import Counter
import json
import math
import pickle
import plyvel
import time
import unicodedata
db_source = plyvel.DB('title_context.ldb', create_if_missing=False)
maxdocs = 1
title_bow = {}
words_freq = {}
for title, serialized in db_source:
maxdocs += 1
context = pickle.loads(serialized)
title_bow.update({ title:dict(Counter(context)) } )
for word in set(context):
if words_freq.get(word) is None: words_freq[word] = 0.
words_freq[word] += 1.
if maxdocs%10000 == 0:
print("now loading... at %d"%maxdocs)
print("total words len = %d"%len(words_freq))
words_idf = {}
for e, (word, freq) in enumerate(words_freq.items()):
if e%1000 == 0:
print("now evaluating... at %d/%d"%(e,len(words_freq)))
weight = math.log( float(maxdocs) / freq )
words_idf[word] = math.log( float(maxdocs) / freq )
open('words_idf.json', 'w').write(json.dumps(words_idf))
IDF計算手順
1.Wikipediaのダンプデータのダウンロードと展開
wget https://dumps.wikimedia.org/jawiki/20230220/jawiki-20230220-pages-articles.xml.bz2
bunzip2 jawiki-20230220-pages-articles.xml.bz2
(最新データのURLは次を参照:https://dumps.wikimedia.org/jawiki/ )
これで、「jawiki-20230220-pages-articles.xml」のデータファイルができます。
2.各記事の分かち書きデータをLevelDBへ保存
展開した「jawiki-20230220-pages-articles.xml」と同じディレクトリ内に、添付の「my-nora-idf-dic.py」を置き、次を実行します。
python3 my_wakati.py
(c5 largeで約40分)
これで、各記事の分かち書きデータが入った「title_context.ldb」というディレクトリができます。
3.idf辞書の作成
続いて、次を実行します。
python3 my_save_idf.py
(c5 largeですとメモリ不足でKilledがでます。c5 4xlargeですと処理時間は約10分です)
これで、idf辞書である「words_idf.json」というjsonファイルが作成されます。
以上です。