毎日テキストマイニング

180日間、毎日テキストマイニングをするブログです

2018/09/06【75日目】Kerasでワンホットコーディングを行う

まだしばらく勉強メモが続きますが、今日はkerasでのワンホットエンコーディングの実装のところです。

以下、勉強メモ。

テキストは最も広く使用されているシーケンスデータ。単語レベルで処理するのが普通。テキストのベクトル化は複数の方法がある。

  • テキストを単語に分割し、各単語をベクトルに変換する。
  • テキストを文字に分割し、各文字をベクトルに変換する。
  • Nグラムの文字を摘出し、各Nグラムをベクトルに変換する。

ただし、Nグラムは順序を維持するトークン化ではないので、連続する単語や文字のシーケンスを調べることで学習するCNNやRNNには向いていない。 ディープラーニングに向いているのはワンホットエンコーディング

NumPyを使った単語のワンホットエンコーディング

import MeCab
import re
from bs4 import BeautifulSoup
import numpy as np

def tweet_to_words(raw_tweet):
    tagger = MeCab.Tagger ("-Owakati")
    letters_only = re.sub("(https?)(:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)", " ", raw_tweet) 
    tweet_text = BeautifulSoup(letters_only, "lxml").get_text() 
    mecab = tagger.parse(tweet_text)
    words = mecab.lower().split()
    return(words)

text = "カフェに来てくださった皆さんありがとうございました!マジムリ学園の宣伝したよ☺️@ JAMのステージから何故だかご縁があります❤️今夜は21:15〜舞台のキャストを発表するshowroomがあったり、24:59〜… https://t.co/BFpObmkBW9"
token_index = {}

for word in tweet_to_words(text):
    if word not in token_index:
        token_index[word] = len(token_index) + 1

max_lenght = 10
results = np.zeros((len(text), max_lenght, max(token_index.values()) + 1))

for i, sample in enumerate(text):
    for j, word in list(enumerate(tweet_to_words(text)))[:max_lenght]:
        index = token_index.get(text)
        results[i, j, index] = 1.

print(results[-1])

実行結果

[[ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]]

これであっているのかわかりませんが、成功していると信じたい。

NumPyで実行しましたが、Kerasにワンホットエンコーディングを行う機能がついており、こちらを使うことを推奨されている(ならなぜNumPyで実行させた)。

それがこちら。

from keras.preprocessing.text import Tokenizer

text = "カフェに来てくださった皆さんありがとうございました!マジムリ学園の宣伝したよ☺️@ JAMのステージから何故だかご縁があります❤️今夜は21:15〜舞台のキャストを発表するshowroomがあったり、24:59〜… https://t.co/BFpObmkBW9"

tokenizer = Tokenizer(num_words=10000)

tokenizer.fit_on_texts(tweet_to_words(text))
seq = tokenizer.texts_to_sequences(tweet_to_words(text))
one_hot_results = tokenizer.texts_to_matrix(tweet_to_words(text), mode='binary')

word_index = tokenizer.word_index
print(word_index)

実行結果。

{'た': 1, 'の': 2, '️': 3, 'が': 4, '〜': 5, 'カフェ': 6, 'に': 7, '来': 8, 'て': 9, 'くださっ': 10, '皆さん': 11, 'ありがとう': 12, 'ござい': 13, 'まし': 14, '!': 15, 'マジムリ': 16, '学園': 17, '宣伝': 18, 'し': 19, 'よ': 20, '☺': 21, 'jam': 22, 'ステージ': 23, 'から': 24, '何故': 25, 'だ': 26, 'か': 27, 'ご': 28, '縁': 29, 'あり': 30, 'ます': 31, '❤': 32, '今夜': 33, 'は': 34, '21': 35, '15': 36, '舞台': 37, 'キャスト': 38, 'を': 39, '発表': 40, 'する': 41, 'showroom': 42, 'あっ': 43, 'たり': 44, '、': 45, '24': 46, '59': 47, '…': 48}

文字だけベクトル化したい場合は、関数を通さず、文字列をそのまま渡せばいいだけのようです。 こんな感じになります。

{'o': 1, 'た': 2, 'あ': 3, 'り': 4, 'が': 5, 'の': 6, 'm': 7, 't': 8, 'b': 9, 'だ': 10, 'さ': 11, 'っ': 12, 'ご': 13, 'ま': 14, 'し': 15, 'ジ': 16, '️': 17, 'ス': 18, 'か': 19, 'す': 20, '2': 21, '1': 22, '5': 23, '〜': 24, 's': 25, 'h': 26, 'w': 27, '9': 28, 'p': 29, 'カ': 30, 'フ': 31, 'ェ': 32, 'に': 33, '来': 34, 'て': 35, 'く': 36, '皆': 37, 'ん': 38, 'と': 39, 'う': 40, 'ざ': 41, 'い': 42, '!': 43, 'マ': 44, 'ム': 45, 'リ': 46, '学': 47, '園': 48, '宣': 49, '伝': 50, 'よ': 51, '☺': 52, 'j': 53, 'a': 54, 'テ': 55, 'ー': 56, 'ら': 57, '何': 58, '故': 59, '縁': 60, '❤': 61, '今': 62, '夜': 63, 'は': 64, '舞': 65, '台': 66, 'キ': 67, 'ャ': 68, 'ト': 69, 'を': 70, '発': 71, '表': 72, 'る': 73, 'r': 74, '、': 75, '4': 76, '…': 77, 'c': 78, 'f': 79, 'k': 80}

あとの流れは分類なので省略。

一応書籍のコードは以下から取得して実行はしています。

github.com

今日の結果

今日のAKBの呟きは51件でした。 要約するとこんな感じです。

" 北海道 で 起き た 強い 地震 とても とても 心配  。 お住い の 方 、 ご 家族 の 方 も ご 無事 でしょ う か ? 自然 災害 が 続い て い て 不安 に なり  。 正しい ニュース が 届い て 、 適切 な 判断 が さ れ て ほしい  。 そして これ 以上 被害 が 広がら ない こと を 願っ て い  。 " " すごく ゆる ー く 文章 を 書い たら 長く なり  た 。 笑 タピオカ に 駅弁 の 話 も ! 読ん で ください ☺ ️ # アメブロ " " もし 今回 体調 が 一刻 を 争う 事態 だっ たら 一 駅 分 の 時間 は めちゃくちゃ 重要 で 私 が 周り に 助け 求め なかっ た 事 が 生死 を 分け て た かも しれ ない と 思う と 怖く て 、 助け て くれる 人 は 周り に いる ので みなさん も そういう 事態 が あっ た 時 は 遠慮 せ ず 周り に 協力 を 求め て いい ん だ ! という 事 を 伝え たかっ た  ! " " な んで ツイート し た か と いう と 実は 「 倒れ そう だ 」 と 言わ れ て から 、 次 の 駅 で 声 かけ て も 反応 なく 担ご う として も 担げ ず 一 駅 やりすごし ちゃっ た ん  。 その後 男性 2 人 が 気づい て くださっ て 次 の 駅 で 降り れ た ん  。 →" " 男性 は ホーム で 少し 体調 取り戻し て  た 。 駅員 さん も 優しかっ た 。 声 を かけ て くれ て 本当に よかっ た 。 すっぴん だっ た ので 誰 も 私 だ と 気付い て ない と 思う けど 、 ちゃんと 伝え られ なかっ た ので 何 も でき ない 私 に 声 を かけ 手伝っ て くださっ て あ … " " 電車 で 隣 の 男性 から 「 倒れ そう 」 と 小声 で 言わ れ 次 の 駅 で 、 降り ょ う と 手 を 取っ た が もう 自力 で 立ち上がれ ず 担ご う に も 男性 を 1 人 で は 担げ ず あたふた し て たら そこ に 居 た 男性 2 人 が 率先 し て 一緒 に 担い で 降り て くれ  た … 感謝 し … " " 北海道 の 皆さん 、 家 や ご 家族 は 大丈夫 でしょ う か … 余震 に 気 を つけ て ください ね 。 " " 本日 発売 !
'嬉しい': 6, '早い': 3, '楽しい': 3, 'すごい': 2, '怖い': 2, 'ない': 2, '優しい': 2, '凄い': 2, '美味しい': 2, '珍しい': 1, '強い': 1, '正しい': 1, 'ほしい': 1, '長い': 1, 'いい': 1, 'よい': 1, '悲しい': 1, 'おかしい': 1, 'ありがたい': 1, '寂しい': 1, '忙しい': 1, '汚い': 1, 'かっこよい': 1, 'よろしい': 1, '多い': 1
'今日': 12, '北海道': 12, '公演': 10, '日': 8, 'さん': 8, '皆さん': 8, 'こと': 7, '大丈夫': 7, '嬉しい': 6, '地震': 6, '心配': 6, '無事': 6, 'お願い': 6, 'チーム': 6, '方': 5, 'これ': 5, '被害': 5, '駅': 5, '私': 5, 'ん': 5, '男性': 5, '余震': 5, '明日': 5, 'ちゃん': 5,
 'する': 33, '今日': 12, '北海道': 12, '公演': 10, 'くださる': 10, 'なる': 9, 'てる': 9, '日': 8, 'さん': 8, '皆さん': 8, '見る': 8, 'こと': 7, '大丈夫': 7, 'いる': 7, '嬉しい': 6, '地震': 6, '心配': 6, '無事': 6, 'お願い': 6, 'チーム': 6, 'くれる': 6, '方': 5, 'これ': 5, '被害': 5, '駅': 5, '私': 5, 'ん': 5, '男性': 5, '余震': 5, '明日': 5, 'ちゃん': 5, 'れる': 5, 'つける': 5,

f:id:rimt:20180909234204p:plain

f:id:rimt:20180909234227p:plain