自分のブログをベクトルにして分布をみた(3)
前回、前々回と、ブログをベクトル表現して分布をみるという試みをしてみました。
自分のブログをベクトルにして分布をみた(1)
自分のブログをベクトルにして分布をみた(2)
今回は、TFIDFを用いたベクトル表現を使ってみます。
0.前処理
辞書とコーパスを作成します。
import MeCab
def tokenize(x):
node = tagger.parseToNode(x)
word_list = []
while node:
pos = node.feature.split(",")[0]
if pos in ['名詞', '動詞', '形容詞']:
word_list.append(node.surface)
node = node.next
return word_list
tagger = MeCab.Tagger('./mecab-ipadic-neologd/')
tagger.parse("")
tokens_list = []
with open('cocolog/cocolog_corpus_3.txt') as fin:
for line in fin:
items = line.rstrip('\n').split('\t')
if len(items[0]) < 1:
continue
tokens_list.append([items[0], items[1], tokenize(items[1]), tokenize(items[2])])
import nltk
nltk.download('stopwords')
stop_words = nltk.corpus.stopwords.words('english')
stop_words.extend(["それ","てる","よう","こと","の","し","い","ん","さ","て","せ","れ",
"する","なり","いる","なる","そう","でき","これ","ここ","さん","あっ",
"あり","できる","ため","なっ","き","み","nbsp"])
import string
import re
from gensim import corpora
re_1 = re.compile('[' + re.escape(string.punctuation) + '0-90123456789\\r\\t\\n]')
def delete_stop_words(x):
y = [re_1.sub("", t) for t in x if t not in stop_words and re_1.sub("",t) != '']
return y
text_list = []
date_list = []
date_title = {}
for date, title, title_bow, article_bow in tokens_list:
t = delete_stop_words(title_bow)
date_title[date] = [title, t]
t.extend(delete_stop_words(article_bow))
text_list.append(t)
date_list.append(date)
date_title[date] = [title, t]
dictionary = corpora.Dictionary(text_list)
dictionary.filter_extremes(no_below=2,no_above=0.3)
corpus = [dictionary.doc2bow(tokens) for tokens in text_list]
dictionary.save_as_text('dict_4.txt') # 辞書保存
corpora.MmCorpus.serialize('corpus_4.mm', corpus) # コーパス保存
1.Gensim TFIDF Modelを使う
from gensim.models import TfidfModel
from gensim.corpora import Dictionary
from gensim.corpora import MmCorpus
dictionary = Dictionary.load_from_text('dict_4.txt')
corpus = MmCorpus('corpus_4.mm')
tfidf_model = TfidfModel(corpus)
tfidf_corpus = tfidf_model[corpus]
2.LSIモデルによる次元削減(2トピック=2次元に変換)
from gensim.models import LsiModel
lsi_model = LsiModel(tfidf_model[corpus], id2word=dictionary, num_topics=2)
lsi_corpus = lsi_model[tfidf_model[corpus]]
3.結果をクラスタリングして表示
title = []
with open('cocolog/cocolog_corpus_3.txt') as fin:
for line in fin:
items = line.rstrip('\n').split('\t')
if len(items[1]) > 0:
title.append(items[1])
import numpy as np
vector = []
for v in lsi_corpus:
vector.append([v[0][1], v[1][1]])
vector = np.array(vector)
from sklearn.cluster import KMeans
n_clusters = 9
km = KMeans(n_clusters=n_clusters, init='k-means++', n_init=10, max_iter=300, tol=1e-04, random_state=0)
y_km = km.fit_predict(vector)
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import cm
%matplotlib inline
matplotlib.use('Agg')
# 可視化
clusterID = y_km
n_cluster = len(np.unique(clusterID))
resolution = 0.2
markers = ('o')
x_min, x_max = vector[:, 0].min() - 0.01, vector[:, 0].max() + 0.01
y_min, y_max = vector[:, 1].min() - 0.01, vector[:, 1].max() + 0.01
# グリッドポイントの生成
plt.figure()
xx, yy = np.meshgrid(np.arange(x_min, x_max, resolution),
np.arange(y_min, y_max, resolution))
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
for idx in np.unique(clusterID):
color = cm.hsv(idx / n_cluster)
plt.scatter(x=vector[clusterID == idx, 0], y=vector[clusterID == idx, 1],
alpha=0.9, color=color, marker=markers[0], label=idx)
for i, p in enumerate(zip(clusterID, title, vector)):
print(i, p[0], p[1], p[2])
plt.title('tonop\'s blog text clustering and mapping 3')
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.legend(loc='upper right')
plt.show()
plt.savefig('text_clustering_and_mapping_3.png')
表示結果
記事ごとの2次元ベクトル(抜粋)とその分布を示します。
孤立しているクラスタ4には「HDL2-G2.0にnetatalk 2.2.Xをインストール」シリーズが入っています。
0 5 落ち着き先が決まるまで [0.05764899 0.03150896]
1 5 聖火リレーを見に行って来ました [0.05791487 0.03885737]
2 5 デジタルカメラ購入 [0.07608363 0.04363352]
3 5 通勤 [0.04891006 0.02797359]
4 5 ロンドン博物館巡り [0.06266481 0.0345797
・・・(中略)・・・
215 5 Shell ScriptとPOSIXコマンドで実践する簡単データ処理(その1) [0.07894017 0.03957342]
216 8 macOS Catalinaにアップデートしてみた結果 [0.23936478 0.08428241]
217 5 WSLでJupyter Labを使う&ショートカット・アイコンから実行する [0.07911324 0.06535255]
218 1 ScrapBook及びSave Page WEで保存したWebページをApache Solrで検索できるようにしてみた(その1) [0.11525891 0.06193918]
219 1 ScrapBook及びSave Page WEで保存したWebページをApache Solrで検索できるようにしてみた(その2) [0.10739071 0.06184314]
トピック毎にWord Cloudを作成
LSIモデルを使って40次元に圧縮して記事の所属トピックを算出します。
lsi_model = LsiModel(tfidf_model[corpus], id2word=dictionary, num_topics=40)
lsi_corpus = lsi_model[tfidf_model[corpus]]
import os
import matplotlib
import matplotlib.pyplot as plt
from wordcloud import WordCloud
FONT = 'font/IPAexfont00401/ipaexg.ttf'
plt.figure(figsize=(20, 16))
os.makedirs('WordCloud_image_5_3', exist_ok=True)
for z in range(lsi_model.num_topics):
plt.subplot(8, 5, z + 1)
x = dict(lsi_model.show_topic(z, 100))
wc = WordCloud(font_path=FONT, background_color="white")
im = wc.generate_from_frequencies(x)
wc.to_file('WordCloud_image_5_3/wordCloud_' + str(z) + '.png')
plt.imshow(im)
plt.axis("off")
plt.title("Topic #" + str(z))
各Word Cloudを見るとなんとなくどんな話題があるか推測できますね。
各トピックに含まれる単語とその重要度は次のようになっています。
lsi_model.print_topics(num_topics=40)
[(0, '-0.360*"netatalk" + -0.261*"HDL" + -0.249*"Windows" + -0.201*"G" + -0.158*"Ubuntu" + -0.113*"Bash" + -0.112*"Mac" + -0.103*"Kindle" + -0.095*"Fusion" + -0.094*"NAS"'),
(1, '0.569*"netatalk" + 0.363*"HDL" + -0.286*"Windows" + 0.238*"G" + -0.218*"Ubuntu" + -0.167*"Bash" + -0.101*"WSL" + 0.092*"リリース" + -0.085*"Kindle" + -0.078*"Window"'),
(2, '0.369*"Kindle" + -0.320*"Ubuntu" + -0.283*"Windows" + -0.265*"Bash" + -0.143*"WSL" + -0.137*"netatalk" + -0.127*"Window" + 0.125*"Instapaper" + 0.121*"mineo" + -0.113*"Build"'),
(3, '-0.593*"Kindle" + 0.202*"mineo" + -0.170*"Instapaper" + -0.143*"launchpad" + 0.136*"通話" + 0.125*"SIM" + 0.112*"円" + 0.107*"分" + -0.103*"jailbreak" + -0.101*"terminal"'),
(4, '-0.304*"mineo" + -0.208*"通話" + 0.188*"iTunes" + -0.180*"SIM" + -0.149*"Kindle" + -0.147*"円" + -0.146*"分" + -0.144*"Ubuntu" + 0.140*"SSD" + 0.139*"NAS"'),
(5, '-0.421*"iTunes" + -0.239*"NAS" + -0.198*"ライブラリ" + 0.178*"SSD" + 0.136*"Fusion" + 0.122*"HDD" + 0.120*"メモリ" + -0.118*"フォルダ" + 0.116*"VMware" + -0.111*"AS"'),
(6, '-0.298*"iTunes" + 0.264*"データ" + 0.246*"処理" + 0.239*"実践" + 0.225*"集計" + 0.217*"ライナー" + 0.206*"ワン" + 0.151*"簡単" + 0.145*"編" + 0.139*"ScrapBook"'),
(7, '0.167*"mineo" + -0.160*"人" + -0.158*"イギリス" + -0.140*"家" + -0.121*"オックスフォード" + -0.120*"日本" + -0.118*"ロンドン" + -0.111*"庭" + -0.105*"行っ" + -0.104*"物件"'),
(8, '-0.303*"Fusion" + -0.269*"フォント" + -0.252*"VMware" + -0.216*"debian" + 0.214*"SSD" + 0.154*"HDD" + 0.153*"R" + 0.150*"メモリ" + 0.148*"Ubuntu" + 0.125*"Bash"'),
(9, '0.283*"ScrapBook" + 0.227*"HTML" + -0.184*"処理" + 0.181*"Apache" + -0.176*"実践" + 0.163*"Solr" + -0.162*"集計" + -0.160*"ライナー" + -0.153*"ワン" + 0.150*"静的"'),
(10, '-0.296*"Bluetooth" + -0.201*"テザリング" + -0.145*"W" + 0.141*"フォント" + -0.139*"入力" + 0.136*"NAS" + -0.125*"キーボード" + 0.124*"Fusion" + -0.121*"TV" + -0.120*"通信"'),
(11, '-0.271*"フォント" + 0.209*"iTunes" + -0.188*"AS" + -0.179*"TE" + -0.171*"Trac" + -0.161*"ADM" + 0.160*"Instapaper" + -0.154*"Bluetooth" + 0.147*"Fusion" + -0.142*"テザリング"'),
(12, '0.475*"フォント" + -0.201*"Instapaper" + 0.163*"Ricty" + 0.141*"ttf" + 0.141*"iTunes" + 0.133*"ScrapBook" + -0.117*"AS" + -0.112*"TE" + 0.110*"Italic" + -0.105*"Trac"'),
(13, '-0.444*"Instapaper" + -0.322*"フォント" + -0.182*"送信" + 0.149*"launchpad" + -0.141*"Reader" + -0.136*"記事" + 0.123*"アップデート" + 0.122*"適用" + -0.117*"Ricty" + -0.114*"Pocket"'),
(14, '0.288*"Flash" + -0.203*"Windows" + 0.192*"Player" + 0.179*"X" + 0.160*"Lion" + 0.144*"Plugin" + 0.143*"OS" + 0.132*"メモリ" + 0.131*"Mavericks" + 0.125*"oald"'),
(15, '-0.234*"debian" + 0.220*"Flash" + -0.167*"Trac" + 0.155*"Player" + -0.151*"日本語" + -0.150*"AS" + -0.147*"Fusion" + -0.147*"ADM" + -0.141*"TE" + -0.138*"ng"'),
(16, '-0.303*"SD" + -0.293*"Pi" + -0.272*"Raspberry" + -0.191*"berryboot" + -0.182*"Debian" + -0.176*"Raspbian" + 0.163*"Flash" + -0.148*"カード" + -0.146*"イメージ" + 0.123*"Player"'),
(17, '0.349*"Flash" + 0.262*"Player" + -0.178*"メモリ" + 0.175*"Plugin" + -0.172*"Mavericks" + -0.170*"アップデート" + 0.152*"oald" + 0.151*"R" + -0.133*"通信" + -0.122*"Yosemite"'),
(18, '-0.195*"通信" + -0.186*"Flash" + 0.159*"Time" + -0.154*"Jupyter" + 0.153*"Machine" + -0.152*"debian" + -0.149*"WSL" + 0.148*"バックアップ" + -0.146*"Player" + 0.145*"TV"'),
(19, '-0.408*"Jupyter" + -0.375*"WSL" + -0.172*"芯" + -0.171*"notebook" + -0.165*"軸" + 0.155*"メモリ" + -0.137*"Lab" + -0.133*"ショートカット・アイコン" + 0.113*"通信" + 0.097*"Windows"'),
(20, '-0.315*"芯" + -0.295*"軸" + 0.156*"バックアップ" + 0.149*"Time" + 0.145*"Machine" + -0.143*"リフィル" + 0.142*"Jupyter" + 0.134*"容量" + 0.128*"TV" + -0.127*"円"'),
(21, '-0.183*"通信" + 0.181*"Bluetooth" + 0.159*"SD" + 0.157*"テザリング" + 0.151*"Pi" + -0.142*"debian" + 0.141*"メモリ" + 0.141*"Raspberry" + 0.135*"Instapaper" + -0.134*"Mojave"'),
(22, '-0.256*"netatalk" + 0.197*"HDL" + 0.184*"apt" + 0.165*"get" + 0.161*"ログイン" + 0.158*"telnet" + 0.152*"LANDISK" + 0.150*"G" + -0.142*"SD" + -0.132*"Pi"'),
(23, '0.343*"芯" + 0.298*"軸" + 0.163*"容量" + 0.145*"バックアップ" + 0.135*"リフィル" + 0.133*"替" + 0.131*"Time" + 0.129*"Machine" + 0.125*"ペン" + -0.124*"HDL"'),
(24, '-0.200*"メモリ" + -0.189*"Jupyter" + 0.185*"Apache" + 0.144*"El" + -0.143*"WSL" + 0.134*"X" + -0.131*"ScrapBook" + 0.130*"芯" + 0.130*"軸" + 0.117*"Capitan"'),
(25, '-0.175*"TV" + -0.146*"Instapaper" + 0.146*"W" + -0.144*"Mojave" + 0.139*"変換" + -0.137*"mini" + -0.133*"機種" + 0.133*"メール" + -0.129*"Early" + -0.118*"家"'),
(26, '-0.178*"Bluetooth" + -0.165*"メモリ" + 0.152*"TV" + -0.148*"テザリング" + -0.144*"円" + 0.136*"ゴム" + 0.117*"通信" + 0.114*"Apple" + -0.110*"Mavericks" + -0.106*"apt"'),
(27, '0.231*"Design" + 0.231*"総集編" + -0.180*"アップデート" + 0.161*"フォルダ" + 0.141*"メモリ" + 0.134*"テザリング" + -0.133*"apt" + 0.131*"Bluetooth" + 0.123*"Software" + 0.115*"読む"'),
(28, '0.192*"テザリング" + 0.178*"Bluetooth" + 0.128*"Design" + 0.128*"総集編" + -0.120*"TV" + 0.113*"Jupyter" + -0.105*"メモリ" + 0.095*"日" + 0.083*"時代" + 0.082*"X"'),
(29, '-0.250*"ゴム" + -0.159*"Lion" + -0.155*"家" + 0.138*"駅" + -0.131*"足" + -0.126*"バンド" + -0.117*"通信" + 0.112*"メモリ" + 0.110*"Flash" + 0.106*"試合"'),
(30, '0.169*"書籍" + -0.168*"W" + -0.161*"SIM" + 0.118*"debian" + -0.116*"Hybrid" + 0.113*"ゴム" + 0.108*"かけ" + 0.106*"放題" + 0.103*"通話" + 0.099*"電子"'),
(31, '0.325*"ゴム" + -0.184*"通信" + 0.168*"バンド" + 0.159*"メモリ" + 0.158*"足" + 0.125*"mineo" + -0.115*"Design" + -0.115*"総集編" + -0.092*"LTE" + 0.091*"ネットワーク"'),
(32, '-0.391*"ゴム" + -0.202*"足" + -0.180*"バンド" + 0.113*"庭" + -0.111*"Trackpad" + -0.105*"Magic" + 0.101*"大家" + 0.095*"家" + 0.093*"芯" + 0.092*"mineo"'),
(33, '0.156*"Lion" + -0.143*"アップデート" + -0.136*"書籍" + 0.102*"接続" + 0.101*"復元" + 0.099*"機能" + -0.094*"コード" + -0.093*"機種" + 0.093*"NAS" + -0.092*"Amazon"'),
(34, '-0.282*"ゴム" + 0.202*"Lion" + -0.149*"バンド" + -0.145*"足" + 0.144*"設置" + 0.128*"ボタン" + 0.127*"ココログフリー" + 0.125*"SNS" + 0.113*"Mountain" + 0.113*"bit"'),
(35, '0.159*"Debian" + -0.148*"返事" + 0.129*"パケット" + -0.122*"メール" + 0.121*"ゴム" + -0.112*"Apache" + -0.102*"Solr" + -0.091*"Ubuntu" + -0.090*"日" + 0.090*"回線"'),
(36, '-0.155*"時代" + -0.143*"駅" + -0.133*"ローマ" + 0.127*"ssh" + -0.112*"円" + 0.106*"安い" + 0.106*"ネットワーク" + 0.103*"朝食" + 0.102*"学生" + 0.099*"食べ"'),
(37, '0.135*"Solr" + -0.125*"放題" + -0.123*"ドライブ" + 0.116*"Apache" + -0.112*"試合" + 0.110*"パケット" + -0.110*"ボタン" + -0.108*"総集編" + -0.108*"Design" + -0.101*"かけ"'),
(38, '-0.141*"試合" + -0.140*"v" + -0.138*"MediaTomb" + -0.129*"Debian" + 0.117*"ゴム" + 0.114*"W" + 0.104*"キー" + -0.101*"mediatomb" + -0.101*"接続" + -0.095*"書籍"'),
(39, '-0.169*"放題" + -0.145*"かけ" + 0.131*"ドライブ" + -0.128*"でんわ" + -0.107*"v" + -0.104*"MediaTomb" + -0.103*"Solr" + 0.102*"ネットワーク" + -0.102*"通信" + 0.101*"SIM"')]
なお、トピック0は上位100単語に正の単語が出てこず、このトピックに入る記事はありませんでした。
単語の共起関係からどんな話題(トピック)があるのかについて類推はできるのですが、ベクトルの分布から傾向を見るのは難しいな〜という感じです。
| 固定リンク
「パソコン・インターネット」カテゴリの記事
- 旧いPCをWindows 11にアップデートしてみた(ThinkPad E440)(2025.06.03)
- 実家のAmazon Echo Show 5に別アカウントのAmazon Alexaアプリから呼びかけするためのAlexaアプリによる設定(2025.01.02)
- Intel Mac で ELYZA-japanese-Llama-2-13b 及び phi-2 とllama.cppで戯れてみた(2024.01.14)
- 分離型キーボードで親指シフト(NICOLA配列)を試す(Majestouch Xacro M10SP JIS配列)(2024.01.06)
- Microsoft Office Word のショートカットキーの一部をEmacs風のキーバインドにしてみた(2023.12.18)
コメント