13 May 2017, 09:11

gensim で謎かけしたら微妙な結果になった

はじめに

word2vec を知ったので、これを利用して謎かけできないかと考えました。

結論からいうと、面白いものはできませんでした m(._.)m

今回の Jupyter Notebook は以下です。

謎かけとは

謎かけとは、

「x とかけまして、y と解く。その心は・・・ z でございます。」

というもので、x と y の共通点を z という言葉遊び。

落語家が大喜利でお客さんから お題 x をもらって、それに対して洒落た答えを返す。

例えば、「眼鏡とかけまして、椅子と解く、その心はどちらもかけるものでございます」など。 あまり面白くないね。

自分は学生のとき落語研究会に入っていたので、学園祭のときに謎かけをよくやって恥をかいていた。

gensim を使う

gensim という python で NLP をするときによく使われるライブラリがあるが、 そこに word2vec が実装されてライブラリとして提供されている。

word2vec を使うと、ある単語に関係する単語を導くことができる。(most_similar)

これをつかって、謎かけめいたことができないか考えたのだった。

gemsin のインストール

Anaconda 環境で以下のコマンドで。cython をインストールすると計算が早くなるらしい。

conda install gensim
conda install cython

model の作成

text8 という 英語の Wikipedia のデータセットを使う。なぜかというと、用意が簡単だから。

$ wget http://mattmahoney.net/dc/text8.zip -P /tmp
$ unzip text8.zip

解凍した text8 ファイルには英単語が羅列されている。これを学習のインプットにする。

from gensim.models import word2vec
data = word2vec.Text8Corpus('/tmp/text8')
model = word2vec.Word2Vec(data, size=200)
model.save("sample.model")

これで sample.model というモデルができる。size=200 というのは 単語を表現するベクトルの長さ。

embeddings の 加算

単語を表すベクトル同士の足し算をしてみる。

model.most_similar(positive=['dog','cat'])

[('goat', 0.7966023683547974),
 ('bee', 0.7859479784965515),
 ('pig', 0.7830795645713806),
 ('bird', 0.7660524845123291),
 ('hound', 0.7580216526985168),
 ('panda', 0.7541525363922119),
 ('hamster', 0.7503507137298584),
 ('ass', 0.7488968372344971),
 ('haired', 0.7469390630722046),
 ('rat', 0.7466884851455688)]

加算した結果に類似する単語が帰ってくる。動物が特徴なことが分かる。

謎かけをしてみる

加算だとあまりよい結果がでなかったので、ある単語に近い単語を求めて、二つの単語に共通する単語を求めてみる。

wx = 'japanese'
x = model.wv[wx]
wy = 'smart'
y = model.wv[wy]

sx = set()
for word, emb in model.most_similar([x], [], 500):
    sx.add(word)
sy = set()
for word, emb in model.most_similar([y], [], 500):
    sy.add(word)

sz = (sx & sy)

sz で集合 x と 集合 y の両方に含まれる単語 z が求められる。これを表示してみる。

for wz in sz:
    print(wx + "とかけまして" + wy + "と解く。その心は・・・" + wz + "でございます")
japanese とかけまして smart と解く。その心は・・・ capcom でございます
japanese とかけまして smart と解く。その心は・・・ starcraft でございます
japanese とかけまして smart と解く。その心は・・・ doraemon でございます

日本人とかけて秀才と解く、そのこころは、ドラえもんです。。。微妙だ。

いろいろ試してみたけれども、うまくいかなかった。z が名詞だとつまらないな、動詞が来てほしいが方法がわからない。

時間があれば、日本語版 Wikipedia を情報源に使ってみたいけれども、作成に時間がかかりそう。

13 May 2017, 04:42

Word2Vec(skip-gram)で自分の twitter アカウントのツィート分析した

はじめに

Udacity DLND、今週は week8。word2vec がテーマ。

週をおうごとによくわからなくなっていくのは、自分だけだろうか。 だんだん、コピペと写経の講座になってしまっている。

リンクが張られてこれ読んでおいてねという感じ。自学自習が重視される。

というわけで、理解を深めるために、試行錯誤してみた。

week8 は、word2vec(skip-gram model) を tensorflow で実装するという内容。 word2vec は、2 層のニューラルネットワークに過ぎないので理解はたやすいのだけれども、 その前処理(SubSumpling)や 高速化のテクニック(Negative Sampling)が意味わからなかった。

この絵で説明する word2vec の解説ページがとてもわかりやすかった。感謝!

演習では、text8 という Wikipedia のデータセットを用いるのだけれども、相変わらず英語で、 日本人の自分にはピンとこない。というわけで、日本語のデータセットを自分で用意して試すことにした。

今回試したフル実装の Jupyter Notebook は以下です。

ツィートをデータセットに用いる

自分の twitter アカウントのツィートをデータセットにもちいることにした。

といっても、元ネタがあって、元ネタはこの記事。

この記事に 自分のツイートを取得する方法が詳しく書いてある。 twitter が csv データを提供してくれるのだ。 ダウンロードすると、tweets.csv というファイルが手に入る。

pandas で読み込んで前処理を加える。 studyplus とか fitbit のログを垂れ流していたので、それらは削除。

raw_data = pd.read_csv('tweets.csv')
text = raw_data['text']

# studyplus の垂れ流しツイートは削除
text = text[text.str.contains("#studyplus") == False]
# fitbit のライフログは削除
text = text[text.str.contains("おはようございます。今日は") == False]

オープンソースの形態素解析エンジンである MeCab をインストールして、 ツイートを単語ごとに分解して保存する。

ここでもさらに文章からゴミを落としていく。以下を参考にした。re.sub を使う。

import Mecab
import re
f_out = open("tweets_wakati.txt", "w" )
for line in text.iteritems():
    line = re.sub('https?://[\w/:%#\$&\?\(\)~\.=\+\-…]+','', line[1])
    line = re.sub('RT', "", line)
    line = re.sub(r'[!-~]', "", line)#半角記号,数字,英字
    line = re.sub(r'[︰-@]', "", line)#全角記号
    line = re.sub('\n', " ", line)#改行文字
    f_out.write(m.parse(line))
f_out.close()

これで tweet データセットがてにはいった。

Word2Vec を Tensorflow で実装

Word2Vec を tensorflow で実装!といっても課題をコピペしただけなので、省略!!

元の課題のコードを見てください。

可視化

こうなりました。自分を構成している概念が可視化されて面白い。

たとえば、落語という言葉に注目してみると、 周辺には寄席、談志、独演会など、落語関係の言葉がちゃんとあつまっている。