文章を分類②:日本語の形態素解析、word2vecを試す

Neural Network Consoleはベクトルの入力にも対応しています。そこで文章をword2vecでベクトル表現化します。しかしNeural Network ConsoleのDATA SETでは、そのまま使えません。1行に1単語を数値にして並べたものに整形します。
チュートリアル:ベクトルもしくは行列をニューラルネットワークの入力とする
機械学習ライブラリgensimの単語ベクトルを作成するword2vecを試してみます。
gensimは、主にテキスト解析を対象としたスケーラブルな機械学習ライブラリで、Word2VecやDoc2VecをシンプルなAPIで利用することができるそうです。

コマンドプロンプトからgensimをインストールします。

$ pip install --upgrade gensim


そのあと、pipでインストールしたツールをまとめてupgradeしました。

$ pip install --upgrade setuptools

「最短コースで日本語Word2Vecを使う」という目的で書かれた下記を試してみます。
15分でできる日本語Word2Vec
青空文庫より「三四郎」をダウンロードして同じフォルダ内のsample1.pyを実行
sample1.py

import re
import codecs
from janome.tokenizer import Tokenizer
from gensim.models import word2vec

# ファイル読込み、内部表現化
f = codecs.open('sanshiro.txt', "r", "sjis")
text = f.read()
f.close()

# ファイル整形
# ヘッダ部分の除去
text = re.split('\-{5,}',text)[2]
# フッタ部分の除去
text = re.split('底本:',text)[0]
# | の除去
text = text.replace('|', '')
# ルビの削除
text = re.sub('《.+?》', '', text)
# 入力注の削除
text = re.sub('[#.+?]', '',text)
# 空行の削除
text = re.sub('\n\n', '\n', text) 
text = re.sub('\r', '', text)

# 整形結果確認

# 頭の100文字の表示 
print(text[:100])
# 見やすくするため、空行 
print()
print()
# 後ろの100文字の表示 
print(text[-100:])

# Tokenneizerインスタンスの生成 
t = Tokenizer()

# テキストを引数として、形態素解析の結果、名詞・動詞原型のみを配列で抽出する関数を定義 
def extract_words(text):
    tokens = t.tokenize(text)
    return [token.base_form for token in tokens 
        if token.part_of_speech.split(',')[0] in['名詞', '動詞']]

#  関数テスト
ret = extract_words('三四郎は京都でちょっと用があって降りたついでに。')
for word in ret:
    print(word)

# 全体のテキストを句点('。')で区切った配列にする。 
sentences = text.split('。')
# それぞれの文章を単語リストに変換(処理に数分かかります)
word_list = [extract_words(sentence) for sentence in sentences]

# 結果の一部を確認 
for word in word_list[0]:
    print(word)

model = word2vec.Word2Vec(word_list, size=100,min_count=5,window=5,iter=100)
print(model)

model.save('model1')


単語ベクトル「model1」も保存できました。株式会社ロンウイットDOWNLOADよりダウンロードしたldcc-20140209.tar.gzの中のフォルダ「movie-enter」の実際のテキストを読み込んで、どんなリストになるか確認します。
sample2.py

import re
from janome.tokenizer import Tokenizer
from gensim.models import word2vec

# ファイル読込み、内部表現化
with open('movie-enter-5840081.txt',encoding="UTF-8",mode='r',errors="ignore") as input:
    textorg = input.read()
    data2 = re.sub(r'[\s ]',"",textorg)
    data3 = re.sub(r'http.+0900',"",data2)
    data4 = re.sub(r'[0-9]',"",data3)
    text = re.sub('【[^】]*】',"",data4)
# Tokenneizerインスタンスの生成 
t = Tokenizer()

# テキストを引数として、形態素解析の結果、名詞・動詞原型のみを配列で抽出する関数を定義 
def extract_words(text):
    tokens = t.tokenize(text)
    return [token.base_form for token in tokens 
        if token.part_of_speech.split(',')[0] in['名詞', '動詞']]

# 全体のテキストを句点('。')で区切った配列にする。 
sentences = text.split('。')
# それぞれの文章を単語リストに変換(処理に数分かかります)
word_list = [extract_words(sentence) for sentence in sentences]

with open("text_for_write.txt",encoding="UTF-8",mode= 'w') as f:
    for ele in word_list:
      f.write(str(ele)+'\n')

#model = word2vec.Word2Vec(word_list, size=100,min_count=5,window=5,iter=100)

sample2.pyの実行結果です。

希望通りです。しかし、model.save(‘model_name’)でsaveしたモデルはNeural Network Consoleでは読めません。そこで、下記サイトを参考にsaveモデルを変更します。
Wikipediaでword2vecの学習してEmbedding Projectorで可視化してみる
sample3.py

import re
from janome.tokenizer import Tokenizer
from gensim.models import word2vec

# テキストを引数として、形態素解析の結果、名詞・動詞原型のみを配列で抽出する関数を定義 
def extract_words(text):
    tokens = t.tokenize(text)
    return [token.base_form for token in tokens
        if token.part_of_speech.split(',')[0] in['名詞', '動詞']]

t = Tokenizer()
filename = "movie-enter-5840081.txt"

with open(filename,encoding="UTF-8",mode='r',errors="ignore") as input:
  textorg = input.read()
  data2 = re.sub(r'[\s ]',"",textorg)
  data3 = re.sub(r'http.+0900',"",data2)
  text = re.sub('【[^】]*】',"",data3)

# 全体のテキストを句点('。')で区切った配列にする。 
sentences = text.split('。')
# それぞれの文章を単語リストに変換(処理に数分かかります)
word_list = [extract_words(sentence) for sentence in sentences]

model = word2vec.Word2Vec(word_list, size=100,min_count=3,window=5,iter=100)

with open('vector_file.csv', 'w', encoding='utf-8') as f, \
     open('metadata_file', 'w', encoding='utf-8') as g:

    # metadata file needs header
    #g.write('Word\n')

    for word in model.wv.vocab.keys():
        embedding = model.wv[word]

        # Save vector TSV file
        f.write('\t'.join([('%f' % x) for x in embedding]) + '\n')

        # Save metadata TSV file
        #g.write(word + '\n')

sample3.pyの実行結果です。

これで大丈夫でしょう。さて、まとめて処理してみます。
sample4.py

import re
import glob
from janome.tokenizer import Tokenizer
from gensim.models import word2vec

# テキストを引数として、形態素解析の結果、名詞・動詞原型のみを配列で抽出する関数を定義 
def extract_words(text):
    tokens = t.tokenize(text)
    return [token.base_form for token in tokens
        if token.part_of_speech.split(',')[0] in['名詞', '動詞']]

t = Tokenizer()
path = "./test"
file_list = glob.glob(path + '/' + '*.txt')

for filename in file_list:
  with open(filename,encoding="UTF-8",mode='r',errors="ignore") as input:
    textorg = input.read()
    data2 = re.sub(r'[\s ]',"",textorg)
    data3 = re.sub(r'http.+0900',"",data2)
    text = re.sub('【[^】]*】',"",data3)

    # 全体のテキストを句点('。')で区切った配列にする。 
    sentences = text.split('。')
    # それぞれの文章を単語リストに変換(処理に数分かかります)
    word_list = [extract_words(sentence) for sentence in sentences]

    model = word2vec.Word2Vec(word_list, size=100,min_count=5,window=5,iter=100)

    with open(filename + '.csv', 'w', encoding='utf-8') as f:

       for word in model.wv.vocab.keys():
           embedding = model.wv[word]

           # Save vector TSV file
           f.write('\t'.join([('%f' % x) for x in embedding]) + '\n')

短いテキストでエラーになり、止まってしまいました。そこで、modelの「min_count=5」を「min_count=3」にします。
sample5.py

import re
import glob
from janome.tokenizer import Tokenizer
from gensim.models import word2vec

# テキストを引数として、形態素解析の結果、名詞・動詞原型のみを配列で抽出する関数を定義 
def extract_words(text):
    tokens = t.tokenize(text)
    return [token.base_form for token in tokens
        if token.part_of_speech.split(',')[0] in['名詞', '動詞']]

t = Tokenizer()
path = "./test"
file_list = glob.glob(path + '/' + '*.txt')

for filename in file_list:
  with open(filename,encoding="UTF-8",mode='r',errors="ignore") as input:
    textorg = input.read()
    data2 = re.sub(r'[\s ]',"",textorg)
    data3 = re.sub(r'http.+0900',"",data2)
    text = re.sub('【[^】]*】',"",data3)

    # 全体のテキストを句点('。')で区切った配列にする。 
    sentences = text.split('。')
    # それぞれの文章を単語リストに変換(処理に数分かかります)
    word_list = [extract_words(sentence) for sentence in sentences]

    model = word2vec.Word2Vec(word_list, size=100,min_count=3,window=5,iter=100)

    with open(filename + '.csv', 'w', encoding='utf-8') as f:

       for word in model.wv.vocab.keys():
           embedding = model.wv[word]

           # Save vector TSV file
           f.write('\t'.join([('%f' % x) for x in embedding]) + '\n')

前もってエラーになる非常に短いテキスト2つを除いておけば、フォルダ「movie-enter」は868ファイルまとめて処理できました。続けてフォルダ「sports-watch」の実際のテキストを処理します。900ファイルまとめて処理できました。
一つのファイルは一つの文章で、そこに含まれる見つけた単語を、一行一単語でベクトル表現している事になります。当然、ファイルの大きさはバラバラになります。このあとTrimmingかPaddingしなければなりません。この先は、「文章を分類③:Neural Network Consoleでカテゴリー分類」に続きます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です