word2vecの学習(その1 データ準備)

書いてる理由

  • itemのレコメンドをやりたい。
  • せっかくword2vecの記事も書いたし自分で学習そういえばしてない。
  • 日本語のデータセットで単語をベクトルにしたろ。

概要

word2vecで自分で学習するためのデータを用意するところをやる。

参考

https://own-search-and-study.xyz/2017/10/08/mecab%E3%81%A8gensim%E3%81%A7word2vec%E3%83%A2%E3%83%87%E3%83%AB%E3%82%92%E5%AD%A6%E7%BF%92%E3%81%99%E3%82%8B/

コード

https://github.com/ys201810/pytorch_work/blob/master/nlp/word2vec/train.py

あー、ちなみにコードは毎日修正していくから後で見返して不整合が起きてたらすません。前のやつら含む。

詳細

livedoor ニュースコーパスのデータでやってみようかな。
このリンクのtar.gzを解凍すると、9個のカテゴリの下にそれぞれtxtファイルが入っていて、カテゴリに属する記事のテキストファイルになっている。
カテゴリは色々あるけど、まずit-life-hack「it-life-hack」のカテゴリのテキストを使ってみる。

実際に入っているテキストファイルの例として一個あげると以下のような感じ。

http://news.livedoor.com/article/detail/6292880/
2012-02-19T13:00:00+0900
旧式Macで禁断のパワーアップ!最新PCやソフトを一挙にチェック【ITフラッシュバック】
テレビやTwitterと連携できるパソコンや、プロセッサや切り替わるパソコンなど、面白いパソコンが次から次へと登場した。旧式Macの禁断ともいえるパワーアップ方法から、NECの最新PC、話題のThinkPad X1 Hybrid、新セキュリティソフトまで一挙に紹介しよう。

■インテル SSD 520をMacに装着!旧式Macはどれほど高速化するのか (上)
インテルが最新SSD「520シリーズ」を発売した。現行SSDの中でもトップクラスの性能を誇る同製品を、旧型Macの高速化を図るというポイントでレビューしてみた。少し風変わりなレビューとなるが、どの程度の効果があるか、期待大である。


■http://itlifehack.jp/archives/6716997.html
ThinkPad X1 Hybridは使用するCPUがx86(インテルCore iなど)からARMに切り替わるハイブリッドなPCだが、これと同時にOSも切り替わる。


■初期費用、更新費用ともに無料!ジャストシステム、ヤモリが目印のセキュリティソフト
現在では、多くのユーザーがパソコンにセキュリティソフトを導入しているが、その過半数は毎年5,000円程度かかる更新費用やその手続きについて不満を持っている。有料ソフトを利用するユーザーの約8割は無料のセキュリティソフトを知っているにもかかわらず、性能面で劣るのではという不安から導入を控えているという状況にある。


■テレビの新しい楽しみ方を提案!NECの春PCはTVとTwitterの連携
NECは2012年2月14日、個人向けデスクトップパソコン「VALUESTAR」シリーズ3タイプ16モデルを2月16日より販売すると発表した。新商品では、よりパワフルになった録画機能に加え、TV視聴・録画機能に業界で初めて人気のTwitterを連携させた「SmartVisionつぶやきプラス」を追加するなど、TVパソコンならではの機能を搭載。スマートフォン、ホームネットワーク対応も強化し、「安心・簡単・快適」なデジタルエンターテイメントの提案として、主要モデルに対し以下の強化を行った。


■まるでお祭りの出荷式!レッツノートSX1の出荷が始まる
2月24日に発売されるLet’snote SX1/NX1の出荷式が2月8日に国内製造拠点の神戸工場で行われた。同社のパソコンとして初めてとなる出荷式で、この製品への力の入れようがわかる。





【エプソン純正インク】インクカートリッジ 6色セット IC6CL50
エプソン
販売元:Amazon.co.jp
クチコミを見る

最初の2行は固定で記事の元のリンクと公開日(?)っぽい。
さすがに記事なので、顔文字とか厄介そうなのはあんまり入ってない。
これを、1ファイルをリストの1要素として、[[1ファイル目の単語リスト], [2ファイル目の単語リスト], [3ファイル目の単語リスト]]というリストのリスト形式に変換していきたい。
また、記号とかの不要な文字は削除していく。
さらに、名詞だけを抽出して名詞の関係性を学習することにする。(助詞とかあんまりいらないし。動詞もとりあえずなしでいいや。名詞達の関係性に絞ることにする。)
これをコードに落としていく。

コード

対象ファイル取得と1ファイルずつの処理の記述

globで対象のテキストファイルのリストを取得して、1ファイルずつ処理。

def main():
    data_root = os.path.join('/path/to/', 'text')
    text_files = glob.glob(os.path.join(data_root, 'it-life-hack', 'it-life-hack-*.txt'))

    train_word_list = []

    for i, text_file in enumerate(text_files):
        print(text_file)
        text_list = make_sentence_list(text_file)
        print(text_list)

        train_word_list.append(text_list)
        print(train_word_list)

ファイルの読み込みと不要な行のスキップ

make_sentence_listで開始から2行は不要なのでスキップして、それ以外の行で、テキストの前処理をかける。

def make_sentence_list(text_file):
    text_list = []
    mecab = MeCab.Tagger("-Ochasen")
    with open(text_file, 'r') as inf:
        for j, line in enumerate(inf):
            # 最初の2行は記事のURLと作成時刻(?)っぽいので飛ばす
            if j == 0 or j == 1:
                continue
            line = line.rstrip()  # 最後の改行を削除

            replaced_text = text_preprocess(line)
            if not replaced_text:
                continue

            print('整形前:{}'.format(line))
            print('整形後:{}'.format(replaced_text))

            noun_list = wakati_mecab(replaced_text, mecab)
            text_list = text_list + noun_list

    return text_list

テキストの前処理

text_preprocessで記号を全て排除するのと、数字を全て0に変換。

def text_preprocess(text):
    delete_charactors = ['\r', '\n', ' ', ' ', '"', '#', '$', '%', '&', ',', "'", '\(', '\)', '\*', '\+', ',', '-',
                         '\.', '/', ':', ';', '<', '=', '>', '\?', '@', '\[', '\]', '^', '_', '`', '{', '|', '}', '~', '!',
                         '!', '#', '$', '%', '&', '\', '’', '(', ')', '*', '×', '+', '−', ':', ';', '<', '=',
                         '>', '?', '@', '「', '」', '^', '_', '`', '『', '』', '【', '】', '|', '〜', '■️']
    for character in delete_charactors:
        text = re.sub(character, '', text)

    text = re.sub(r'[0-9 0−9]', '0', text)  # 数字を全て0に
    return text

分かち書きと名詞だけ取得

この前処理をした結果をwakati_mecabに突っ込んで名詞だけの単語をリストにappendしてreturn。
returnされたリストを結合していき、1ファイルのリストとして最終的なリストにappendしていく。

def wakati_mecab(text, mecab):
    noun_list = []
    wakati_result = mecab.parse(text)
    words = wakati_result.split('\n')
    for ward in words:
        results = ward.split('\t')
        if results[0] == 'EOS' or results[0] == '':
            continue
        if results[3].find('名詞') != -1:
            noun_list.append(results[0])

    return noun_list

ちなみに前処理での整形前のテキストと整形後のテキストを比較してみると、以下のような感じ。

整形前:旧式Macで禁断のパワーアップ!最新PCやソフトを一挙にチェック【ITフラッシュバック】
整形後:旧式Macで禁断のパワーアップ最新PCやソフトを一挙にチェックITフラッシュバック
整形前:テレビやTwitterと連携できるパソコンや、プロセッサや切り替わるパソコンなど、面白いパソコンが次から次へと登場した。旧式Macの禁断ともいえるパワーアップ方法から、NECの最新PC、話題のThinkPad X1 Hybrid、新セキュリティソフトまで一挙に紹介しよう。
整形後:テレビやTwitterと連携できるパソコンや、プロセッサや切り替わるパソコンなど、面白いパソコンが次から次へと登場した。旧式Macの禁断ともいえるパワーアップ方法から、NECの最新PC、話題のThinkPadX0Hybrid、新セキュリティソフトまで一挙に紹介しよう。
整形前:■インテル SSD 520をMacに装着!旧式Macはどれほど高速化するのか (上)
整形後:■インテルSSD000をMacに装着旧式Macはどれほど高速化するのか上

記号とかがなくなっていることがわかる。(■は置換対象にしたんだけど無くならんのは不明・・・。)
さらにこれを名詞だけ分かち書きした単語のリストにすると以下のような感じ。

['旧式', 'Mac', '禁断', 'パワーアップ', '最新', 'PC', 'ソフト', '一挙', 'チェック', 'IT', 'フラッシュ', 'バック', 'テレビ', 'Twitter', '連携', 'パソコン', 'プロセッサ', 'パソコン', 'パソコン', '次', '次', '登場', '旧式', 'Mac', '禁断', 'パワーアップ', '方法', 'NEC' ...

まぁこんなもんか感。
分かち書きした名詞リストを見ていると、0とか0000がよく出てくる。数字を全て0にしているので頻出してしまうが、これはそのまま残すべきかどうかがちょっと不明なので一旦このまま進める。
もしかしたら数字を削除にした方がいいかも??後で考えよう。

今日は以上。
次は学習までいくかな。

コード全体

# coding=utf-8
import re
import os
import glob
import MeCab


def wakati_mecab(text, mecab):
    noun_list = []
    wakati_result = mecab.parse(text)
    words = wakati_result.split('\n')
    for ward in words:
        results = ward.split('\t')
        if results[0] == 'EOS' or results[0] == '':
            continue
        if results[3].find('名詞') != -1:
            noun_list.append(results[0])

    return noun_list


def text_preprocess(text):
    delete_charactors = ['\r', '\n', ' ', ' ', '"', '#', '$', '%', '&', ',', "'", '\(', '\)', '\*', '\+', ',', '-',
                         '\.', '/', ':', ';', '<', '=', '>', '\?', '@', '\[', '\]', '^', '_', '`', '{', '|', '}', '~', '!',
                         '!', '#', '$', '%', '&', '\', '’', '(', ')', '*', '×', '+', '−', ':', ';', '<', '=',
                         '>', '?', '@', '「', '」', '^', '_', '`', '『', '』', '【', '】', '|', '〜', '■️']
    for character in delete_charactors:
        text = re.sub(character, '', text)

    text = re.sub(r'[0-9 0−9]', '0', text)  # 数字を全て0に
    return text


def make_sentence_list(text_file):
    text_list = []
    mecab = MeCab.Tagger("-Ochasen")
    with open(text_file, 'r') as inf:
        for j, line in enumerate(inf):
            # 最初の2行は記事のURLと作成時刻(?)っぽいので飛ばす
            if j == 0 or j == 1:
                continue
            line = line.rstrip()  # 最後の改行を削除

            replaced_text = text_preprocess(line)
            if not replaced_text:
                continue

            print('整形前:{}'.format(line))
            print('整形後:{}'.format(replaced_text))

            noun_list = wakati_mecab(replaced_text, mecab)
            text_list = text_list + noun_list

    return text_list


def main():
    data_root = os.path.join('/path/to/', 'text')
    text_files = glob.glob(os.path.join(data_root, 'it-life-hack', 'it-life-hack-*.txt'))

    train_word_list = []

    for i, text_file in enumerate(text_files):
        print(text_file)
        text_list = make_sentence_list(text_file)
        print(text_list)

        train_word_list.append(text_list)
        print(train_word_list)

        if i == 0:
            exit(1)

if __name__ == '__main__':
    main()