自分のツイートを word2vec で学習させて遊ぶ
全ツイートの内容を word2vec に放り込んで遊んだ。
数年前から word2vec はスゴいらしいという話を聞いていたが、なんとなくスルーしていた。
Python の gensim パッケージで手軽に word2vec を使えるようなので、試してみた。
word2vec は、2014年に Google で開発された自然言語処理の手法。比較的計算量が少ないところが特徴らしい。
word2vec は、大量の文章を渡されると、単語の前後関係から、各単語をよく表すn次元のベクトルを学習する。
一見すると機械的な方法だが、なぜか単語どうしの意味的な関連性まで学習できてしまう(ことがある)らしい。
ベクトルの次元数 n は、自由に設定できる。ネット上のサンプルを見ていると n=100 くらいに設定していることが多かった。
学習時の「前後の単語を見る」処理として、CBOW (Continuous Bag-of-words) と skip-gram の2種類が提案されている。どちらを使うかによって、NNの構造がすこし異なる。
あまりツイートしない単語なら問題ないかもしれないが、ツイート頻度の高いキャラクターの名前だったりすると、word2vec の学習結果に影響する可能性がある。
MeCab はユーザ辞書を追加できるため、うまく分かれていない単語を見つけ出し、辞書をつくった。
ユーザ辞書のつくり方は taku910.github.io/mecab/dic.html 、辞書作成に必要な「品詞ID」については taku910.github.io/mecab/posid.html に書いてある。
mywords.csv (UTF-8エンコーディングで保存する)
mywords.csv から辞書ファイル mywords.dic を生成するバッチファイルを作った。
create_dic.bat
バッチファイルを実行して生成された mywords.dic を適当なフォルダへコピーする。
ここでは C:\Program Files (x86)\MeCab\userdic を作成し、その中にコピーした。
最後に、設定ファイルを開いて、ユーザ辞書へのパスを追加する。
C:\Program Files (x86)\MeCab\etc\mecabrc を開いて
これでもう一度 MeCab を実行すると、ユーザ辞書をつかってわかち書きできるようになる。
あらかじめ Python の gensim パッケージをインストールしておく。
gensim のインターフェースは簡素なので、実は数行で書ける(ドキュメントは ここ にある)。
今回は skip-gram を使って、100次元のベクトルを学習させる。
w2v_learn.py
全部で5MBの wakati_w2v.txt を使って、学習に1~2分くらいかかった。
生成される tweet_list.model は 29.2MB だった。意外とでかい!
w2v_similar.py はコマンドライン引数として受け取った単語に似た単語を10個表示してくれる。
自分のデータセットでは、
という結果になった。
『ゆるゆり』の登場人物である 結衣 から、京子、杉浦、綾乃、ちなつ といった他の登場人物を類似した単語として学習できている。
また、「結衣先輩」と呼んでいたためか 先輩 や センパーイ も類似した単語として挙げられている。
python w2v_similar.py 言語
python w2v_similar.py Aphex
python w2v_similar.py 神奈川
学習の設定を変えると出力結果も変わってくるので、うまく調整すればもっと良い結果になりそう(どのような状態が「良い結果」なのかよくわからないが……)。
ベクトル表現をそのまま取り出せば、他にもおもしろいことができるかもしれない。
数年前から word2vec はスゴいらしいという話を聞いていたが、なんとなくスルーしていた。
Python の gensim パッケージで手軽に word2vec を使えるようなので、試してみた。
今回使った環境
- Windows 10 (64bit)
- Python 3.6.0 (Anaconda 4.3.0)
- MeCab 0.996
word2vec は、2014年に Google で開発された自然言語処理の手法。比較的計算量が少ないところが特徴らしい。
ざっくりとした流れ
word2vec という名前の由来は、おそらく "word to vector" の略だと思う(出典はない)。単語 (word) からベクトル (vector) を学習する。一見すると機械的な方法だが、なぜか単語どうしの意味的な関連性まで学習できてしまう(ことがある)らしい。
ベクトルの次元数 n は、自由に設定できる。ネット上のサンプルを見ていると n=100 くらいに設定していることが多かった。
細かい話
学習には2層のニューラルネットワーク (入力層、隠れ層、出力層からなる。ふつう出力層はカウントしないので2層といっている) を使っているらしい。意外と少ない!学習時の「前後の単語を見る」処理として、CBOW (Continuous Bag-of-words) と skip-gram の2種類が提案されている。どちらを使うかによって、NNの構造がすこし異なる。
Python の gensim パッケージではどちらも使えるが、今回は性能が良いらしい skip-gram を使うことにする。
参考:
Word2vec - Wikipedia
絵で理解するWord2vecの仕組み
【論文シリーズ】CBOWとSkip-gramについて
なにか良さそうなものはないかと考えて、約12万ツイートある mogesystem の投稿内容を使うことにした。
たまに漫画やアニメの話をするので、ひょっとすると登場人物の名前などを学習できるかもしれない。
ボタンを押してしばらくすると、メールでダウンロードURLが送られてくる。
ZIPファイルをダウンロードして解凍したなかに tweets.csv というファイルがある。
この tweets.csv には、1行1ツイートとして全投稿内容が含まれている。
今回はこの tweets.csv を使うことにする。
ここでは「自分が投稿したツイートの本文」だけが必要なので、処理していく。
以下にリストアップしたものは不要となる。
これらの作業を手動でこなすのはムリがあるので、Pythonで処理するコードを書いた。
create_tweet_list.py
あらかじめ "pip install pandas" で Pandas をインストールしておき、
文章を word2vec へぶっこむには、単語ごとにスペースで区切ってやる必要がある。
英文は最初から単語スペース区切りになっているが、日本語の文章はどこからどこまでが一単語なのかはわからない。
この「単語ごとにスペースで区切る」処理は、わかち書きと呼ばれている。わかち書きには、日本語形態素解析エンジン MeCab(メカブ)がよく使われている。
今回はコマンドラインから MeCab を利用する。Python にも MeCab のバインディングがあるようだが、どうやら Windows との親和性が悪いようで使えなかった。
さっそく MeCab をインストールする。
MeCab のサイトから、インストーラをダウンロードする。
インストール中に辞書のエンコーディングを聞かれるが、今回は UTF-8 にする。
最後に、MeCabのインストールフォルダにパスを通せば、セットアップ完了。
基本的には、以下のコマンドで tweet_list.txt をわかち書きできる。
今回の用途では、動詞や形容詞を原形に変換しておくと都合がいい。
なぜこんなことをするかというと、文章中の「見た」「見ろ」といった動詞すべてを「見る」という同じ単語として関係性を学習させたいからだ。
MeCab では、以下のようなオプションをつけて、分かち書きしつつ原形へ変換できる。
Word2vec - Wikipedia
絵で理解するWord2vecの仕組み
【論文シリーズ】CBOWとSkip-gramについて
データの準備
さて、word2vec の学習には、大きめの文章データが必要となる。なにか良さそうなものはないかと考えて、約12万ツイートある mogesystem の投稿内容を使うことにした。
たまに漫画やアニメの話をするので、ひょっとすると登場人物の名前などを学習できるかもしれない。
自分のツイートをダウンロードする
全ツイートの履歴は twitter.com/settings/account から取得できる。ボタンを押してしばらくすると、メールでダウンロードURLが送られてくる。
ZIPファイルをダウンロードして解凍したなかに tweets.csv というファイルがある。
この tweets.csv には、1行1ツイートとして全投稿内容が含まれている。
今回はこの tweets.csv を使うことにする。
tweets.csv の内容 ろくなツイートでないことは気にしてはいけない |
ツイートの本文だけを抜き出す
tweets.csv をテキストエディタで開いてみると、投稿日時といったメタ情報や、RTしたツイートまでもが、CSVデータとして記録されている。ここでは「自分が投稿したツイートの本文」だけが必要なので、処理していく。
以下にリストアップしたものは不要となる。
- リツイート
- 本文以外のデータ(投稿日時やツイートIDなど)
- 本文中のURL
- 本文中のスクリーンネーム (@~)
- 本文中のハッシュタグ (#~)
これらの作業を手動でこなすのはムリがあるので、Pythonで処理するコードを書いた。
create_tweet_list.py
import pandas as pd import numpy as np # 読み込み df_all = pd.read_csv('tweets.csv') # リツイート以外のツイート (retweeted_status_idが空っぽの行) を抜き出す df_mytweet = df_all.ix[df_all['retweeted_status_id'].isnull(), ['text']] # 置き換えルール mytweet = df_mytweet['text'] replaceList = [ ('@[a-zA-Z0-9_]{1,15}', ''), ('https?://[\w/:%#\$&\?\(\)~\.=\+\-]+', ''), ('[##][A-Za-zA-Za-z一-鿆0-90-9ぁ-ヶヲ-゚ー]+', ''), ('\n', ' '), ('<', '<'), ('>', '>'), ('&', '&'), ] for t in replaceList: mytweet = mytweet.str.replace(t[0], t[1]) # 前後の空白文字を削除 mytweet = mytweet.str.strip() # 空行を削除 mytweet = mytweet.replace('', np.nan).dropna() # テキストファイルに保存 with open('tweet_list.txt', 'w', encoding='utf-8') as f: for line in mytweet.values: f.writelines(line + '\n')
python create_tweet_list.pyを実行すると、tweets.csvを読み込んで tweet_list.txt というファイルを作ってくれる。
ツイート本文を抜き出したファイル tweet_list.txt ヘンなツイートが多いのはご愛嬌 |
ツイート本文の前処理(分かち書き・原形への変換)
こうしてできあがった tweet_list.txt をさっそく word2vec で学習したいところだが、そのままではうまく扱えない。文章を word2vec へぶっこむには、単語ごとにスペースで区切ってやる必要がある。
英文は最初から単語スペース区切りになっているが、日本語の文章はどこからどこまでが一単語なのかはわからない。
この「単語ごとにスペースで区切る」処理は、わかち書きと呼ばれている。わかち書きには、日本語形態素解析エンジン MeCab(メカブ)がよく使われている。
今回はコマンドラインから MeCab を利用する。Python にも MeCab のバインディングがあるようだが、どうやら Windows との親和性が悪いようで使えなかった。
さっそく MeCab をインストールする。
MeCab のサイトから、インストーラをダウンロードする。
インストール中に辞書のエンコーディングを聞かれるが、今回は UTF-8 にする。
最後に、MeCabのインストールフォルダにパスを通せば、セットアップ完了。
基本的には、以下のコマンドで tweet_list.txt をわかち書きできる。
mecab tweet_list.txt -o wakati.txt -Owakati
今回の用途では、動詞や形容詞を原形に変換しておくと都合がいい。
なぜこんなことをするかというと、文章中の「見た」「見ろ」といった動詞すべてを「見る」という同じ単語として関係性を学習させたいからだ。
MeCab では、以下のようなオプションをつけて、分かち書きしつつ原形へ変換できる。
mecab tweet_list.txt -o wakati_w2v.txt -F"%%f[6] " -U"%%m " -E"\n"(MeCab の詳細仕様は taku910.github.io/mecab/format.html に書いてある。フォーマット指定には % を使うが、コマンドプロンプトの仕様で %% と書く必要がある。)
わかち書きしつつ原形にしたツイート wakati_w2v.txt 単語がすべて原形になったので日本語不自由っぽい |
ユーザ辞書を追加する
ところで、MeCabの出力結果をみてみると、特殊な固有名詞などがバラバラに分解されてしまうことがある。あまりツイートしない単語なら問題ないかもしれないが、ツイート頻度の高いキャラクターの名前だったりすると、word2vec の学習結果に影響する可能性がある。
MeCab はユーザ辞書を追加できるため、うまく分かれていない単語を見つけ出し、辞書をつくった。
ユーザ辞書のつくり方は taku910.github.io/mecab/dic.html 、辞書作成に必要な「品詞ID」については taku910.github.io/mecab/posid.html に書いてある。
mywords.csv (UTF-8エンコーディングで保存する)
赤座,,,100,名詞,固有名詞,人名,姓,*,*,赤座,アカザ,アカザ タンコブ,,,100,名詞,一般,*,*,*,*,タンコブ,タンコブ,タンコブ 肩甲骨,,,100,名詞,固有名詞,一般,*,*,*,肩甲骨,ケンコウコツ,ケンコウコツ ヤマノススメ,,,100,名詞,固有名詞,一般,*,*,*,ヤマノススメ,ヤマノススメ,ヤマノススメ ゆるゆり,,,100,名詞,固有名詞,一般,*,*,*,ゆるゆり,ゆるゆり,ゆるゆり 肉巻きおにぎり,,,100,名詞,一般,*,*,*,*,肉巻きおにぎり,ニクマキオニギリ,ニクマキオニギリ 逆流性食道炎,,,100,名詞,一般,*,*,*,*,逆流性食道炎,ギャクリュウセイショクドウエン,ギャクリュウセイショクドウエン 磯波,,,100,名詞,固有名詞,人名,名,*,*,磯波,アカザ,アカザ 返信,,,100,名詞,一般,*,*,*,*,返信,ヘンシン,ヘンシン 鍵垢,,,100,名詞,一般,*,*,*,*,鍵垢,カギアカ,カギアカ 規制垢,,,100,名詞,一般,*,*,*,*,規制垢,キセイアカ,キセイアカ ふぁぼ,,,100,名詞,一般,*,*,*,*,ふぁぼ,ファボ,ファボ 電気素量,,,100,名詞,固有名詞,一般,*,*,*,電気素量,デンキソリョウ,デンキソリョウ 焼肉定食,,,100,名詞,固有名詞,人名,姓,*,*,焼肉定食,ヤキニクテイショク,ヤキニクテイショク おーいぇえーあはぁん,,,100,名詞,固有名詞,一般,*,*,*,おーいぇえーあはぁん,オーイエーアハーン,オーイエーアハーン ちなつ,,,100,名詞,固有名詞,人名,名,*,*,ちなつ,チナツ,チナツ 赤外線天文衛星,,,100,名詞,固有名詞,一般,*,*,*,赤外線天文衛星,セキガイセンテンモンエイセイ,セキガイセンテンモンエイセイ
mywords.csv から辞書ファイル mywords.dic を生成するバッチファイルを作った。
@echo off REM -d DIR: システム辞書があるディレクトリ REM -u FILE: FILE というユーザファイルを作成 REM -f charset: CSVの文字コード REM -t charset: バイナリ辞書の文字コード mecab-dict-index -d "C:\Program Files (x86)\MeCab\dic\ipadic" -u mywords.dic -f utf-8 -t utf-8 mywords.csv
バッチファイルを実行して生成された mywords.dic を適当なフォルダへコピーする。
ここでは C:\Program Files (x86)\MeCab\userdic を作成し、その中にコピーした。
最後に、設定ファイルを開いて、ユーザ辞書へのパスを追加する。
C:\Program Files (x86)\MeCab\etc\mecabrc を開いて
userdic = "C:\Program Files (x86)\MeCab\userdic\mywords.dic"を追記する。
これでもう一度 MeCab を実行すると、ユーザ辞書をつかってわかち書きできるようになる。
word2vec を使う
準備が整ったので、ようやく word2vec にツイートを学習させる。あらかじめ Python の gensim パッケージをインストールしておく。
pip install gensim
ベクトルを学習させる
前処理したツイート wakati_w2v.txt を word2vec に放り込む。gensim のインターフェースは簡素なので、実は数行で書ける(ドキュメントは ここ にある)。
今回は skip-gram を使って、100次元のベクトルを学習させる。
w2v_learn.py
from gensim.models import word2vec sentences = word2vec.LineSentence('wakati_w2v.txt') model = word2vec.Word2Vec(sentences, sg=1, # 訓練アルゴリズム; 0: CBOW, 1: skip-gram size=100, # ベクトルの次元数 window=10, # 同じ文章内の単語どうしの最大距離 min_count=2, # これより出現回数の少ない単語は含まない hs=1, # 1: 階層的ソフトマックス, hs==0 && negative!=0: ネガティブサンプリングを使う negative=0 # ネガティブサンプリング(ノイズワード)の数 ) model.save('tweet_list.model')
全部で5MBの wakati_w2v.txt を使って、学習に1~2分くらいかかった。
生成される tweet_list.model は 29.2MB だった。意外とでかい!
類似する単語をリストアップする
生成されたモデルをつかって、いろいろな操作ができる。
まずは、ある単語に似た単語をリストアップする、というタスクをやってみる。
w2v_similar.py
まずは、ある単語に似た単語をリストアップする、というタスクをやってみる。
w2v_similar.py
from gensim.models import word2vec import sys model = word2vec.Word2Vec.load('tweet_list.model') results = model.most_similar(positive=sys.argv[1], topn=10) for r in results: print(r[0], '\t', r[1])
w2v_similar.py はコマンドライン引数として受け取った単語に似た単語を10個表示してくれる。
自分のデータセットでは、
python w2v_similar.py 結衣を実行すると
先輩 0.821367084980011 濃厚 0.7531079649925232 杉浦 0.7434007525444031 バッキンガム 0.7008762955665588 センパーイ 0.6812834143638611 京子 0.6799753308296204 綾乃 0.6702271103858948 罰金 0.6633200645446777 野獣 0.6593067646026611 ちなつ 0.6481812000274658
という結果になった。
『ゆるゆり』の登場人物である 結衣 から、京子、杉浦、綾乃、ちなつ といった他の登場人物を類似した単語として学習できている。
また、「結衣先輩」と呼んでいたためか 先輩 や センパーイ も類似した単語として挙げられている。
python w2v_similar.py 言語
真似る 0.6424436569213867 ポインタ 0.6400958895683289 アセンブリ 0.6016155481338501 枠組み 0.5786939263343811 初等 0.5606597065925598 アルゴリズム 0.552629828453064 NET 0.5475132465362549 組み込める 0.5434015989303589 DxLib 0.5420008897781372 C 0.5419571399688721なんとなくプログラミング言語やライブラリの名前が見える。
python w2v_similar.py Aphex
Twin 0.8739225268363953 Radiator 0.8268277645111084 Fingerbib 0.8095642924308777 Stone 0.8080536127090454 Tassels 0.7786843180656433 Twig 0.7654238343238831 vordhosbn 0.7652990221977234 カーンカ 0.7626219987869263 Calx 0.7598056197166443 Balsalm 0.7510707378387451Aphex Twin の曲名の一部が出てきている。
兵庫 0.8190442323684692 長崎 0.8164616227149963 栃木 0.8114367723464966 石川 0.8072326183319092 香川 0.8070265054702759 埼玉 0.802727460861206 広島 0.7998003959655762 鳥取 0.7940439581871033 静岡 0.7927784323692322 山梨 0.7881968021392822日本の県名が出てきた。
おわり
というわけで、今更ながら word2vec で遊んだ。学習の設定を変えると出力結果も変わってくるので、うまく調整すればもっと良い結果になりそう(どのような状態が「良い結果」なのかよくわからないが……)。
ベクトル表現をそのまま取り出せば、他にもおもしろいことができるかもしれない。
コメント
コメントを投稿