LoginSignup
0
0

More than 1 year has passed since last update.

tf-idfをWikiepdiaダンプファイルからMeCabで計算--EC2(CentOS)で--

Last updated at Posted at 2023-02-25

はじめに

次の記事
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を使い、正規化のために単語の原型を採用しています。

my_wakati.py
# 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ファイルに保存します。

my_save_idf.py
# 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ファイルが作成されます。

以上です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0