2つの特徴的分散表現を測る
用途
特定の文章群に対して文章分類を行う際,SVM(SupportVectorMachine)+FeatureSelectionを用いると,ただ分類ができるだけではなく,その分類に寄与する素性を順位付けすることができる.(なので,ノイズのない状態で実験できるので精度が上がる.次元圧縮にも役立つ)
その素性が分散表現でどう表現されるのか調べるのがこのプログラム.
使用するデータ
*SVM+FSで抽出されたテキストファイル
*word2vecで作成した日本語Wikipedia全記事のモデル
# 3.22/w.o
1 0.2144 142 146 1:株式会社 -0.2309 9 21 1:レストランチェーン
2 0.1981 108 119 1:を -0.1946 0 3 1:Tughril
3 0.1959 503 588 1:経営 -0.1763 64 382 1:(\"
4 0.1821 33 34 2:、 -0.1759 70 86 1:)",
5 0.1743 407 488 1:企業 -0.1737 1 15 1:Grill
今回準備したデータは,SVMから出力されるオリジナルではなく,そこから作成したものです.省略してtop5のみあげています.
プログラム
ALL.py
# -*- coding:utf-8 -*-
from janome.tokenizer import Tokenizer
from gensim.models import word2vec
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from matplotlib import rcParams
from matplotlib.backends.backend_pdf import PdfPages
import glob
import torch.nn.functional as F
import torch
from scipy.cluster.hierarchy import linkage, dendrogram, fcluster
t = Tokenizer()
plt.rcParams["font.size"] = 18
rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = ['Hiragino Maru Gothic Pro', 'Yu Gothic', 'Meirio', 'Takao', 'IPAexGothic', 'IPAPGothic', 'VL PGothic', 'Noto Sans CJK JP']
model = word2vec.Word2Vec.load("./wiki_model.sg1")
reject = [')",','(','),','、','。',"'",',(',', ','・','。",','\\")','(\\"','\n']
def words_append(wordsp,wordsn):
with open("./SVM+FS.txt") as fs:
fslist0 = fs.readlines()
fslist = []
for m in fslist0:
m = m.replace("\n","")
fslist.append(m)
del fslist0
positive = []
negative = []
for m in fslist:
line = m.split(" ")
line2 = [a for a in line if a != '']
try:
positive.append(line2[4])
negative.append(line2[8])
except:
pass
del line,line2
for i,m in enumerate(positive):
mm = m.split(":")
if not mm[1] in reject:
mm[1] = mm[1].replace("\n","")
tokens = t.tokenize(mm[1])
for token in tokens:
# 品詞を取り出し
partOfSpeech = token.part_of_speech.split(',')[0]
if partOfSpeech == "名詞":
wordsp.append([mm[1],"r"])
break
for i,m in enumerate(negative):
mm = m.split(":")
if not mm[1] in reject:
mm[1] = mm[1].replace("\n","")
tokens = t.tokenize(mm[1])
for token in tokens:
# 品詞を取り出し
partOfSpeech = token.part_of_speech.split(',')[0]
if partOfSpeech == "名詞":
wordsn.append([mm[1],"b"])
break
def plotM(wordsp,wordsn):
labels = []
print(len(wordsp),len(wordsn))
length = len(wordsp)
datap = []
j = 0
while j <= length:
try:
datap.append(model[wordsp[j][0]])
except:
try:
print(wordsp[j])
del wordsp[j]
except:
pass
j += 1
# print(f'{"datap is"} {datap}')
length = len(wordsn)
datan = []
j = 0
while j <= length:
try:
datan.append(model[wordsn[j][0]])
except:
try:
del wordsn[j]
except:
pass
j += 1
if len(wordsp) > len(wordsn):
print("TypeA")
for i in range((len(wordsp) - len(wordsn))):
wordsp.pop()
elif len(wordsn) > len(wordsp):
print("TypeB")
for i in range((len(wordsn) - len(wordsp))):
wordsn.pop()
print(len(wordsp),len(wordsn))
length = len(wordsp)
datap = []
j = 0
while j <= length:
try:
datap.append(model[wordsp[j][0]])
x = wordsp[j][0]
x = x + "+"
labels.append(x)
except:
pass
j += 1
# print(f'{"datap is"} {datap}')
length = len(wordsn)
datan = []
j = 0
while j <= length:
try:
datan.append(model[wordsn[j][0]])
x = wordsn[j][0]
x = x + "-"
labels.append(x)
except:
pass
j += 1
pca = PCA(n_components=2)
pca.fit(datap)
pca.fit(datan)
data_pcap= pca.transform(datap)
data_pcan= pca.transform(datan)
pdata = torch.from_numpy(data_pcap)
ndata = torch.from_numpy(data_pcan)
out = F.kl_div(pdata, ndata)
print(out)
#----
A = data_pcap
B = data_pcan
AB = len(A)+len(B)
#print(A)
#data = A + B
#print(len(data))
print(len(labels))
data = np.zeros(shape=(AB,2))
count = 0
for i,m in enumerate(A):
data[i] = m
count+=1
for i,m in enumerate(B,start = count):
#print(i)
data[i] = m
#print(data)
print(f'{len(A)},{len(B)},{len(data)}')
# 階層型クラスタリングの実施
# ウォード法 x ユークリッド距離
linkage_result = linkage(data, method='ward', metric='euclidean')
# クラスタ分けするしきい値を決める
threshold = 0.7 * np.max(linkage_result[:, 2])
# 階層型クラスタリングの可視化
plt.figure(num=None, figsize=(16, 9), dpi=200, facecolor='w', edgecolor='k')
dendrogram(linkage_result, labels=labels, color_threshold=threshold)
#dendrogram(linkage_result, labels=labels)
plt.show()
# クラスタリング結果の値を取得
clustered = fcluster(linkage_result, threshold, criterion='distance')
# クラスタリング結果を比較
print(clustered)
#------
# length_data = len(data_pca)
# i = 0
# while i < length_data:
# #点プロット
# plt.plot(data_pca[i][0], data_pca[i][1], ms=5.0, zorder=2, marker="x", color=words[i][1])
# #文字プロット
# plt.annotate(words[i][0], (data_pca[i][0], data_pca[i][1]), size=7)
# i += 1
# title = "r料理店とb茶店"
# plt.title(title, fontsize=18)
# plt.savefig("./"+str(title)+".png")
# # plt.show()
words = []
wordsp = []
wordsn = []
words_append(wordsp,wordsn)
plotM(wordsp,wordsn)
# -*- coding:utf-8 -*-
from janome.tokenizer import Tokenizer
from gensim.models import word2vec
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from matplotlib import rcParams
from matplotlib.backends.backend_pdf import PdfPages
import glob
import torch.nn.functional as F
import torch
from scipy.cluster.hierarchy import linkage, dendrogram, fcluster
t = Tokenizer()
plt.rcParams["font.size"] = 18
rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = ['Hiragino Maru Gothic Pro', 'Yu Gothic', 'Meirio', 'Takao', 'IPAexGothic', 'IPAPGothic', 'VL PGothic', 'Noto Sans CJK JP']
model = word2vec.Word2Vec.load("./wiki_model.sg1")
reject = [')",','(','),','、','。',"'",',(',', ','・','。",','\\")','(\\"','\n']
def words_append(wordsp,wordsn):
with open("./SVM+FS.txt") as fs:
fslist0 = fs.readlines()
fslist = []
for m in fslist0:
m = m.replace("\n","")
fslist.append(m)
del fslist0
positive = []
negative = []
for m in fslist:
line = m.split(" ")
line2 = [a for a in line if a != '']
try:
positive.append(line2[4])
negative.append(line2[8])
except:
pass
del line,line2
for i,m in enumerate(positive):
mm = m.split(":")
if not mm[1] in reject:
mm[1] = mm[1].replace("\n","")
tokens = t.tokenize(mm[1])
for token in tokens:
# 品詞を取り出し
partOfSpeech = token.part_of_speech.split(',')[0]
if partOfSpeech == "名詞":
wordsp.append([mm[1],"r"])
break
for i,m in enumerate(negative):
mm = m.split(":")
if not mm[1] in reject:
mm[1] = mm[1].replace("\n","")
tokens = t.tokenize(mm[1])
for token in tokens:
# 品詞を取り出し
partOfSpeech = token.part_of_speech.split(',')[0]
if partOfSpeech == "名詞":
wordsn.append([mm[1],"b"])
break
def plotM(wordsp,wordsn):
labels = []
print(len(wordsp),len(wordsn))
length = len(wordsp)
datap = []
j = 0
while j <= length:
try:
datap.append(model[wordsp[j][0]])
except:
try:
print(wordsp[j])
del wordsp[j]
except:
pass
j += 1
# print(f'{"datap is"} {datap}')
length = len(wordsn)
datan = []
j = 0
while j <= length:
try:
datan.append(model[wordsn[j][0]])
except:
try:
del wordsn[j]
except:
pass
j += 1
if len(wordsp) > len(wordsn):
print("TypeA")
for i in range((len(wordsp) - len(wordsn))):
wordsp.pop()
elif len(wordsn) > len(wordsp):
print("TypeB")
for i in range((len(wordsn) - len(wordsp))):
wordsn.pop()
print(len(wordsp),len(wordsn))
length = len(wordsp)
datap = []
j = 0
while j <= length:
try:
datap.append(model[wordsp[j][0]])
x = wordsp[j][0]
x = x + "+"
labels.append(x)
except:
pass
j += 1
# print(f'{"datap is"} {datap}')
length = len(wordsn)
datan = []
j = 0
while j <= length:
try:
datan.append(model[wordsn[j][0]])
x = wordsn[j][0]
x = x + "-"
labels.append(x)
except:
pass
j += 1
pca = PCA(n_components=2)
pca.fit(datap)
pca.fit(datan)
data_pcap= pca.transform(datap)
data_pcan= pca.transform(datan)
pdata = torch.from_numpy(data_pcap)
ndata = torch.from_numpy(data_pcan)
out = F.kl_div(pdata, ndata)
print(out)
#----
A = data_pcap
B = data_pcan
AB = len(A)+len(B)
#print(A)
#data = A + B
#print(len(data))
print(len(labels))
data = np.zeros(shape=(AB,2))
count = 0
for i,m in enumerate(A):
data[i] = m
count+=1
for i,m in enumerate(B,start = count):
#print(i)
data[i] = m
#print(data)
print(f'{len(A)},{len(B)},{len(data)}')
# 階層型クラスタリングの実施
# ウォード法 x ユークリッド距離
linkage_result = linkage(data, method='ward', metric='euclidean')
# クラスタ分けするしきい値を決める
threshold = 0.7 * np.max(linkage_result[:, 2])
# 階層型クラスタリングの可視化
plt.figure(num=None, figsize=(16, 9), dpi=200, facecolor='w', edgecolor='k')
dendrogram(linkage_result, labels=labels, color_threshold=threshold)
#dendrogram(linkage_result, labels=labels)
plt.show()
# クラスタリング結果の値を取得
clustered = fcluster(linkage_result, threshold, criterion='distance')
# クラスタリング結果を比較
print(clustered)
#------
# length_data = len(data_pca)
# i = 0
# while i < length_data:
# #点プロット
# plt.plot(data_pca[i][0], data_pca[i][1], ms=5.0, zorder=2, marker="x", color=words[i][1])
# #文字プロット
# plt.annotate(words[i][0], (data_pca[i][0], data_pca[i][1]), size=7)
# i += 1
# title = "r料理店とb茶店"
# plt.title(title, fontsize=18)
# plt.savefig("./"+str(title)+".png")
# # plt.show()
words = []
wordsp = []
wordsn = []
words_append(wordsp,wordsn)
plotM(wordsp,wordsn)
付け足し付け足しで作ったプログラムで,しかもセンスないのでゴミプログラムと言われるかもしれませんが,参考になれば嬉しいです.
KL-divはPyTorchで計算しています.
階層的クラスタリングはscipyでやっています.
結果を少し
料理店と茶屋という類義語(分類語彙表では)を用い,その単語を含む記事をWikipediaから抽出,SVM+FSをおこなった結果FS:200で分類精度が最高になった.それでも分類精度は0.664.
そこで抽出したFS正負top100単語の名詞のみの分散表現をwikipedia全記事から作成したモデルから抽出.PCAで2次元まで落とし,散布図を作成する.(ここはプログラムではコメントアウトされている)
赤と青の分散表現群は近いところで散布しているので,KL-divも0.0019となっている.
しかし.2つの群が混じり合い1つのクラスタを形成している部分もある(右端).
これを抽出するのが,階層的クラスタリングである.
これを見ると各クラスタを抽出することができる.
すいません,やっぱりこの記事みてわかる人は変態だと思います.
説明のグダリ具合がヤバめ.貴重な時間を使って読んでくださった方,ありがとうございます.
コメントありましたら,お待ちしてます.
参考文献
Author And Source
この問題について(2つの特徴的分散表現を測る), 我々は、より多くの情報をここで見つけました https://qiita.com/U-chom/items/cced01697377aa3a2cdd著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .