t-SNEを使った文書ベクトルの可視化をしてみました。可視化にはSeabornの散布図を使います。Seabornはmatplotlibをベースにしたグラフ描画ライブラリで、matplotlibよりも美しく扱いやすいライブラリになっています。
可視化する文書ベクトルはこちらの記事でツイートとWikipediaのデータから求めたSCDVです。
関連リンク
SCDVを使ったテキスト分類をしてみる - どん底から這い上がるまでの記録
seaborn: statistical data visualization — seaborn 0.9.0 documentation
seaborn.lmplot — seaborn 0.9.0 documentation
sklearn.manifold.TSNE — scikit-learn 0.19.2 documentation
プログラムについて
前回はmain.py
, dataset.py
, scdv.py
の3つのプログラムがありましたが、今回はdataset.py
とscdv.py
はそのままに、main.py
の中身を少し変えて文書ベクトルを散布図を用いて可視化してみます。
具体的にはmain.py
のライブラリをインポートするところ、main()
のなかを少し変更します。parse_args()
に変更はありません。
以下、main.py
について書いていきます。
ライブラリのインポート
今回使うライブラリです。
import argparse
import dataset
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from sklearn.manifold import TSNE
from scdv import SparseCompositeDocumentVectors, build_word2vec
冒頭部分に変更はありません。
def main(args):
sentences, train_x, test_x, train_t, test_t = dataset.load_corpus()
model = build_word2vec(
sentences,
args.embedding_dim,
args.min_count,
args.window_size,
args.sg
)
vec = SparseCompositeDocumentVectors(
model,
args.num_clusters,
args.embedding_dim,
args.pname1,
args.pname2
)
データの用意
今回は前回と異なりすべてのデータを使ってSCDVを作ります。そのため、以下のコードで訓練データとテストデータに分けたものをひとつのリストにしつつ、データの正解ラベルも同時にひとつのリストにしています。
corpus = {'data': [], 'label': []}
corpus['data'] = train_x + test_x
corpus['label'] = [["Twitter", "Wikipedia"][label] for label in train_t] \
+ [["Twitter", "Wikipedia"][label] for label in test_t]
SCDVを求める
すべてのデータを使って確率重み付き単語ベクトルを求め、SCDVを作ります。
vec.get_probability_word_vectors(corpus['data'])
gwbowv = vec.make_gwbowv(corpus['data'])
TwitterとWikipediaはそれぞれ742件のデータがあるので、ひとつにすると1484件になり、文書ベクトルは200次元となっています。
TSNEを使った次元削減
200次元ある文書ベクトルを可視化するために次元削減の手法のひとつ、t-SNEを使って2次元にします。sckit-learnで実装されているものを使います。
tsne = TSNE(
n_components=2, random_state=0, verbose=2
)
tsne.fit(gwbowv)
散布図を作る
pandasのDataFrameにx軸とy軸となるものを作り、そこに2次元のベクトルを入れます。
df = pd.DataFrame(tsne.embedding_[:, 0], columns=['x'])
df['y'] = pd.DataFrame(tsne.embedding_[:, 1])
df['class'] = corpus['label']
graph = sns.lmplot(
data=df, x='x', y='y', hue='class', fit_reg=False, size=8
)
DataFrameができたらSeabornのlmplot()
で散布図を作ります。
散布図の描画
最後にplt.show()
で結果を見てみましょう。
plt.show()
結果
結果はこうなりました。

すごいきれいにTwitterとWikipediaのデータが分かれてまとまっていますね。
ここまできれいに分かれるとは思いませんでした。
main.py
import argparse
import dataset
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from sklearn.manifold import TSNE
from scdv import SparseCompositeDocumentVectors, build_word2vec
def parse_args():
parser = argparse.ArgumentParser(
description="Word2VecとSCDVのパラメータの設定"
)
parser.add_argument(
'--embedding_dim', type=int, default=100
)
parser.add_argument(
'--min_count', type=int, default=5
)
parser.add_argument(
'--window_size', type=int, default=5
)
parser.add_argument(
'--sg', type=int, default=1
)
parser.add_argument(
'--num_clusters', type=int, default=2
)
parser.add_argument(
'--pname1', type=str, default="gmm_cluster.pkl"
)
parser.add_argument(
'--pname2', type=str, default="gmm_prob_cluster.pkl"
)
return parser.parse_args()
def main(args):
sentences, train_x, test_x, train_t, test_t = dataset.load_corpus()
model = build_word2vec(
sentences,
args.embedding_dim,
args.min_count,
args.window_size,
args.sg
)
vec = SparseCompositeDocumentVectors(
model,
args.num_clusters,
args.embedding_dim,
args.pname1,
args.pname2
)
corpus = {'data': [], 'label': []}
corpus['data'] = train_x + test_x
corpus['label'] = [["Twitter", "Wikipedia"][label] for label in train_t] \
+ [["Twitter", "Wikipedia"][label] for label in test_t]
vec.get_probability_word_vectors(corpus['data'])
gwbowv = vec.make_gwbowv(corpus['data'])
tsne = TSNE(
n_components=2, random_state=0, verbose=2
)
tsne.fit(gwbowv)
df = pd.DataFrame(tsne.embedding_[:, 0], columns=['x'])
df['y'] = pd.DataFrame(tsne.embedding_[:, 1])
df['class'] = corpus['label']
graph = sns.lmplot(
data=df, x='x', y='y', hue='class', fit_reg=False, size=8
)
plt.show()
graph.savefig('graph.png')
if __name__ == "__main__":
main(parse_args())