繼續更新出來本系列的程式碼:亂燉資料之2700餘篇“簡書交友”專題文章資料的花式玩法
在亂燉“簡書交友”資料之程式碼(1)一文裡,主要涉及結構化資料的分析,文字挖掘如詞頻統計、詞雲圖等。本文繼續用jieba庫抽取文字關鍵詞,並呼叫百度雲NLP的API獲取關鍵詞的Word2Vec詞向量,並用t-SNE視覺化高維資料,之後用文字自己訓練了Word2Vec詞向量,效果稍好些,最後嘗試了下LDA主題模型。
程式碼見於 GitHub - DesertsX / JianShuJiaoYou,下一篇也是本系列最後一篇會涉及文章的照片爬取、人臉識別及顏值打分和照片牆等更新後也會開源在此專案,歡迎star。
另外先預告下,之後打算開個“Kaggle Kernel 學習系列”,GitHub - DesertsX / Kaggle-Kernel-Learning,主要是翻譯和學習下kaggle上優秀的kernels。其中第一篇非常粗糙,還沒潤色、修改排版佈局的notebook可供瀏覽下,也歡迎關注、star和提供寶貴建議:
desertsx.github.io/2018/06/09/…
desertsx.github.io/2018/06/09/…
關鍵詞抽取
基於 TF-IDF 演算法的關鍵詞抽取
- jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())
import pandas as pd
import jieba
import jieba.analyse
df12 = pd.read_csv('JianShuJiaoYou-All-Data.csv', encoding='utf-8')
contents = " ".join(df12.Artical_Content.values.tolist())
複製程式碼
Top200
基於 TF-IDF 演算法抽取前200個關鍵詞(普通名詞和地點名詞)。
textrank1 = " ".join(jieba.analyse.extract_tags(contents, topK=200, withWeight=False, allowPOS=('ns', 'n')))
print(textrank1)
複製程式碼
簡書 時候 朋友 簡友 文章 交友 我會 文字 故事 投稿 愛情 感覺 大家 大學 時間 專題 事情 人生 老師 樹洞 世界 東西 同學 照片 地方 女生 電影 情書 性格 暱稱 有點 交流 學校 夢想 內心 經歷 時光 男生 作者 讀書 城市 女孩 姑娘 孩子 單身 畢業 感情 凡人 青春 樣子 名字 攝影 男朋友 校園 靈魂 父母 日子 對方 問題 學生 手機 朋友圈 小說 年齡 美食 專業 職業 評論 哥哥 心情 星座 女朋友 跑步 賬號 素材 體重 陌生人 小夥伴 音樂 唱歌 好友 文藝 自我介紹 見面 畫畫 室友 個人 姐姐 陪伴 風景 媽媽 想象 地點 緣分 閨蜜 社群 回家 習慣 篇文章 現實 記錄 無法 圖書館 性別 公眾 理想 原因 關係 平臺 北京 興趣 遊戲 結果 粉絲 小時候 美麗 情感 禮物 男人 總會 女孩子 方式 機會 宿舍 程式設計師 長大 舍友 陌生 印象 文學 私信 妹子 嘉賓 校友 話題 男孩 學會 模樣 交朋友 聯絡 聲音 眼睛 家鄉 記憶 編輯 小時 女人 顏值 無戒 世間 能力 缺點 寫文章 脾氣 先生 家庭 家人 寫字 身體 大神 咖啡 讀者 碼字 上海 線下 晚安 熱情 社會 幻想 衣服 群裡 生氣 教室 吉他 學歷 成績 筆名 味道 情緒 意義 狀態 異地 民謠 勵志 學姐 爸媽 天空 作品 書寫 友情 妹妹 思想 心靈 成都 老爸 學長 文筆 婚姻 小學 目標
基於 TextRank 演算法的關鍵詞抽取
jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))
演算法基本思想:
- 將待抽取關鍵詞的文字進行分詞
- 以固定視窗大小(預設為5,通過span屬性調整),詞之間的共現關係,構建圖
- 計算圖中節點的PageRank,注意是無向帶權圖
Top200
基於 TextRank 演算法抽取前200個關鍵詞(allowPOS=('ns', 'n'),普通名詞和地點名詞),並返回關鍵詞權重值(withWeight=True)。篇幅所限,僅羅列前幾個詞語。
textrank4 = jieba.analyse.textrank(contents, topK=200, withWeight=True, allowPOS=('ns', 'n'))
print(textrank4)
複製程式碼
[('時候', 1.0),
('簡書', 0.9286492277441794),
('朋友', 0.5604058706337074),
('文章', 0.5119472310224017),
('大家', 0.4435913680744001),
('交友', 0.4205067493937958),
('時間', 0.41736915018165616),
('大學', 0.4169278527224929),
('文字', 0.3963519612404718),
('故事', 0.3672191429321304),
('簡友', 0.36709289668920975),
('感覺', 0.35411529061992564),]
抽取出這些關鍵詞後,突然想到可以使用word2vec詞向量,看看這些詞語在向量空間中會是怎樣分佈的?哪些詞語會在相似的區域?
原本想用gensim庫
自己訓練word2vec,但是沒成功(後面重新研究了下,已經搞定了,後面再介紹),機緣巧合接觸到百度雲的產品,於是呼叫下看看效果如何。
Word2Vec 詞向量
詞向量,就是將詞語對映成一個固定維度的向量。詞向量可能具備一定的語義資訊,如相似的詞語在相近的向量空間(如西瓜和蘋果都屬於水果,但蘋果也存在歧義);可以學到詞語之間的關係,如經典的“男人-女人=國王-王后”(King – Man + Woman = Queen)。
又比如,國家與首都之間的對應關係也能通過詞向量反映出來。後文也呼叫百度雲的api試了一下幾組詞,有類似效果。
相關原理可自行了解,文字不展開了:
- NLP - 秒懂詞向量Word2vec的本質
- 無痛理解word2vec
- 自然語言處理(NLP)基礎概念(一):詞向量(word vector)及其生成方法介紹
The amazing power of word vectors
百度雲NLP-詞向量表示
再貼下官網的解釋:
- 詞向量計算是通過訓練的方法,將語言詞表中的詞對映成一個長度固定的向量。詞表中所有的詞向量構成一個向量空間,每一個詞都是這個詞向量空間中的一個點,利用這種方法,實現文字的可計算。
先官網註冊下以便呼叫API,再按照Python庫:pip install baidu-aip
。
# pip install baidu-aip
# https://cloud.baidu.com/doc/NLP/NLP-Python-SDK.html#.E6.96.B0.E5.BB.BAAipNlp
# 新建一個AipNlp
from aip import AipNlp
""" 你的 APP_ID/API_KEY/SECRET_KEY """
APP_ID = '你的 APP_ID'
API_KEY = '你的 API_KEY'
SECRET_KEY = 'SECRET_KEY'
client = AipNlp(APP_ID, API_KEY, SECRET_KEY)
複製程式碼
官網示例:呼叫詞向量表示
每個詞語均用1024維的詞向量表示,當然也有很多詞不存在語料庫裡,所以也就無法用詞向量表示。先看看官網給出的“俺也一樣”的“張飛”的示例,一行程式碼就能獲取相應詞語的詞向量。不過由於太佔篇幅,文章裡就不放了,非常詳細的程式碼在: GitHub - DesertsX / JianShuJiaoYou。
word = "張飛"
""" 呼叫詞向量表示 """
w = client.wordEmbedding(word);
print(w['word'], len(w['vec']) # 張飛 1024
print(w)
複製程式碼
獲取textrank4中Top200詞語的詞向量
羅列出了詞表中不存在的詞語共13個,拿到187個詞語的詞向量。
import numpy as np
words_list = []
word_vectors = []
for word,_ in textrank4:
try:
data = client.wordEmbedding(word)
word_vector = data['vec']
#print(data['word'])
words_list.append(data['word'])
word_vectors.append(word_vector)
except:
print("No word:{}".format(word))
word_vectors = np.array(word_vectors)
# print("Total words:", len(words_list))
print(words_list)
print("Total words:", len(words_list), '\tWord Embedding shapes:', word_vectors.shape)
# Total words: 187
# Word Embedding shapes: (187, 1024)
複製程式碼
No word:簡書
No word:簡友
No word:有點
No word:小時候
No word:圖書館
No word:男朋友
No word:線下
No word:陌生人
No word:朋友圈
No word:小夥伴
No word:大學生
No word:女孩子
No word:程式設計師
Total words: 187 Word Embedding shapes: (187, 1024)
t-SNE 視覺化高維資料
使用 t-SNE 來檢視視覺化高維資料,分別在2維和3維下檢視下詞向量分佈效果。
sklearn.manifold.TSNE
t-SNE 2維
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] # 用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False # 用來正常顯示負號
%matplotlib inline
#%config InlineBackend.figure_format='svg'
def plot_tsne_2D(word_vectors, words_list):
tsne = TSNE(n_components=2, random_state=0, n_iter=10000, perplexity=3)
np.set_printoptions(suppress=True)
T = tsne.fit_transform(word_vectors)
labels = words_list
plt.figure(figsize=(8, 6))
plt.scatter(T[:,0], T[:,1], c='steelblue', edgecolors='k')
for label, x, y in zip(labels, T[:,0], T[:,1]):
plt.annotate(label, xy=(x+1, y+1),xytext=(0,0), textcoords='offset points')
plot_tsne_2D(word_vectors, words_list)
複製程式碼
效果不好,比較雜亂,相關相似的詞語沒有分佈在相近區域,可能是百度使用的語料和本專案用的簡書交友文章語料的不同導致的。
t-SNE 3維
還是很雜亂,看到“哥哥”、“姐姐”、“女人”、“女孩”、“孩子”等詞語分佈的很分散,感覺一定是哪出了問題。
# https://stackoverflow.com/questions/10374930/matplotlib-annotating-a-3d-scatter-plot
from mpl_toolkits.mplot3d import Axes3D
def plot_tsne_3D(word_vectors, words_list):
tsne = TSNE(n_components=3, random_state=0, n_iter=10000, perplexity=2)
np.set_printoptions(suppress=True)
T = tsne.fit_transform(word_vectors)
labels = words_list
plt.figure(figsize=(10, 6))
ax = plt.subplot(111,projection='3d')
for i in range(len(T)): # plot each point + it's index as text above
x = T[i,0]
y = T[i,1]
z = T[i,2]
label = labels[i]
ax.scatter(x, y, z, color='b');
ax.text(x, y, z, '%s' % (label), size=9, zorder=1, color='k');
ax.set_title('word2vec t-SNE 3D');
ax.set_xlabel('x');
ax.set_ylabel('y');
ax.set_zlabel('z');
plot_tsne_3D(word_vectors, words_list)
複製程式碼
復現下官網的例子
由於上述詞向量視覺化的結果不太理想,為了探索下哪出了問題,於是復現下官網配圖的效果。當然一開始並不清楚它是舉例用的、隨便畫的,還是實際通過計算後繪製的。個人傾向於後者,那麼應該是能復現吧?!
將獲取詞向量,2維、3維 t-SNE 視覺化均寫成函式,方便重複使用。
words = ['姨夫', '老公', '妹妹', '奶奶', '表哥', '乾爸', '外爺', '繼父',
'性感', '沮喪', '真夠', '悲憤', '探詢', '懷想', '甜美',
'南寧', '合肥', '淮海', '珠江', '津蒙', '奎河', '邕江', '灤河']
def get_word2vec(words):
words_list = []
word_vectors = []
for word in words:
try:
data = client.wordEmbedding(word)
word_vector = data['vec']
#print(data['word'])
words_list.append(data['word'])
word_vectors.append(word_vector)
except:
print("No word:{}".format(word))
word_vectors = np.array(word_vectors)
print(words_list)
print("Total words:", len(words_list), '\tWord Embedding shapes:', word_vectors.shape)
return word_vectors, words_list
word_vectors, words_list = get_word2vec(words)
plot_tsne_2D(word_vectors, words_list)
複製程式碼
額...地名的大致在右下角,人物關係的在左上角,但還是區分度不夠好。
plot_tsne_3D(word_vectors, words_list)
複製程式碼
很差......完全摸不著頭腦,可能是需要繼續調參吧???
Try Again: 想些詞再試試
自己不死心的,又想了三類詞語,這回的效果理想了很多。不過“騰
訊”一詞有些突兀,於是去掉後再試試。
words = ['中國', '北京', '日本', '東京', '法國', '巴黎', '俄羅斯', '莫斯科',
'百度', '李彥宏', '京東', '劉強東', '騰訊', '馬化騰', '阿里巴巴','馬雲',
'三國', '曹操', '劉備', '西遊記', '唐僧', '悟空', '紅樓', '寶玉', '黛玉','王熙鳳']
word_vectors, words_list = get_word2vec(words)
plot_tsne_2D(word_vectors, words_list)
複製程式碼
去掉“騰訊”一詞後,除了“京東”一詞明顯突兀,其他都還不錯,相似相關的詞分佈在了一起
words = ['中國', '北京', '日本', '東京', '法國', '巴黎', '俄羅斯', '莫斯科',
'百度', '李彥宏', '京東', '劉強東', '馬化騰', '阿里巴巴','馬雲',
'三國', '曹操', '劉備', '西遊記', '唐僧', '悟空', '紅樓', '寶玉', '黛玉','王熙鳳']
word_vectors, words_list = get_word2vec(words)
plot_tsne_2D(word_vectors, words_list)
複製程式碼
plot_tsne_3D(word_vectors, words_list)
複製程式碼
訓練 Word2Vec 模型
Gensim - models.word2vec – Deep learning with word2vec
預處理
讀取資料,並去掉停用詞,注意sentences
是列表巢狀列表的格式**
import pandas as pd
import jieba
df12 = pd.read_csv('JianShuJiaoYou-All-Data.csv', encoding='utf-8')
content = df12.Artical_Content.values.tolist()
stopwords1 = [line.rstrip() for line in open('./Stopwords/中文停用詞庫.txt', 'r', encoding='utf-8')]
stopwords2 = [line.rstrip() for line in open('./Stopwords/哈工大停用詞表.txt', 'r', encoding='utf-8')]
stopwords3 = [line.rstrip() for line in open('./Stopwords/四川大學機器智慧實驗室停用詞庫.txt', 'r', encoding='utf-8')]
stopwords = stopwords1 + stopwords2 + stopwords3
print(stopwords[10:20])
sentences = []
for line in content:
try:
segs = jieba.lcut(line)
segs = filter(lambda x:len(x)>1, segs)
segs = filter(lambda x:x not in stopwords, segs)
# sentences.append(segs)
sentences.append(list(segs))
except Exception as e:
print(line)
continue
import multiprocessing
from gensim.models import Word2Vec
model_csv = Word2Vec(sentences, min_count=20, sg=0, workers=multiprocessing.cpu_count())
model_csv.wv.most_similar(['簡書'], topn=15)
複製程式碼
訓練好後,找出與“簡書”一詞,最相近最相關的詞語,羅列如下,效果還行:
[('平臺', 0.9340553283691406), ('簽約', 0.905404269695282),
('書上', 0.8926113843917847), ('一位', 0.8816096186637878),
('簡書裡', 0.8752850294113159), ('加入', 0.8719199895858765),
('創作', 0.8692747354507446), ('這篇', 0.8666418790817261),
('大神', 0.8640251755714417), ('下載', 0.8557288646697998),
('篇文章', 0.8523578643798828), ('第一篇', 0.8458684682846069),
('作者', 0.8452268838882446), ('專題', 0.8378645181655884),
('讀者', 0.8378232717514038)]
查詢前文抽取的關鍵詞textrank4
的最相近詞語,並拿到關鍵詞的詞向量。
import numpy as np
words_list = []
word_vectors = []
for word,_ in textrank4:
try:
result = model_csv.wv.most_similar(positive=[word],topn=15)
print("關鍵詞: {}".format(word))
print(result)
print("+++++++++++++++++++++++++++++++++++")
w2v = model_csv.wv[word]
words_list.append(word)
word_vectors.append(w2v)
#for v in w2v:
# print(v[0],v[1])
except:
print("No word: {}".format(word))
word_vectors = np.array(word_vectors)
複製程式碼
挑選了些查詢的結果,供讀者瀏覽,看看大家都在談些什麼,蠻有趣的:
關鍵詞: 電影
[('拍照', 0.9252004623413086), ('爬山', 0.920052170753479), ('美食', 0.9192012548446655), ('音樂', 0.9168093204498291), ('看書', 0.9157875180244446), ('聽歌', 0.9069955945014954), ('旅遊', 0.9057952165603638), ('唱歌', 0.899057149887085), ('吉他', 0.8984708786010742), ('跑步', 0.8956234455108643), ('民謠', 0.8925215601921082), ('一部', 0.8880782127380371), ('運動', 0.8865675330162048), ('羽毛球', 0.8812819123268127), ('動漫', 0.8731318116188049)]
+++++++++++++++++++++++++++++++++++
關鍵詞: 青春
[('記憶', 0.9561529755592346), ('回憶', 0.955527126789093), ('曾經', 0.9253653287887573), ('時光', 0.905220627784729), ('歲月', 0.896970272064209), ('最美', 0.8751366138458252), ('美麗', 0.8565613031387329), ('走過', 0.8368370532989502), ('春天', 0.8309674263000488), ('難忘', 0.8301017880439758), ('一片', 0.8259316682815552), ('美好', 0.8249017000198364), ('一段', 0.8218579292297363), ('依舊', 0.8214970231056213), ('心中', 0.8203814029693604)]
+++++++++++++++++++++++++++++++++++
關鍵詞: 美麗
[('最美', 0.9421555995941162), ('天空', 0.9361464381217957), ('便是', 0.9163937568664551), ('流浪', 0.908709704875946), ('陽光', 0.907963752746582), ('春天', 0.9046747088432312), ('歲月', 0.9010506868362427), ('幻想', 0.8919180035591125), ('定格', 0.8899471163749695), ('純真', 0.8851020932197571), ('年華', 0.8850700259208679), ('一片', 0.8834213614463806), ('難忘', 0.8828067183494568), ('遠方', 0.8826968669891357), ('繁華', 0.8787059187889099)]
+++++++++++++++++++++++++++++++++++
關鍵詞: 日子
[('遺憾', 0.9469071626663208), ('度過', 0.9386813640594482), ('多年', 0.9268732070922852), ('依舊', 0.9203112125396729), ('依然', 0.9201472401618958), ('變成', 0.9193578362464905), ('痛苦', 0.9121938943862915), ('後悔', 0.9080638885498047), ('過得', 0.9079610109329224), ('慢慢', 0.9073663949966431), ('珍惜', 0.9073460102081299), ('孤單', 0.9017938375473022), ('時光', 0.8997607231140137), ('過去', 0.8995781540870667), ('漫長', 0.8980476260185242)]
+++++++++++++++++++++++++++++++++++
關鍵詞: 習慣
[('鍛鍊', 0.8789036870002747), ('享受', 0.8728272914886475), ('不愛', 0.8702492117881775), ('獨處', 0.8683050870895386), ('發呆', 0.862934947013855), ('空閒', 0.856212854385376), ('人去', 0.8532602787017822), ('打籃球', 0.8526784777641296), ('沒事', 0.8500849008560181), ('超級', 0.8474704027175903), ('放鬆', 0.844687819480896), ('熱鬧', 0.8433003425598145), ('走路', 0.8428263664245605), ('閒暇', 0.8407423496246338), ('養成', 0.8402824401855469)]
+++++++++++++++++++++++++++++++++++
關鍵詞: 男朋友
[('女朋友', 0.9782456159591675), ('結婚', 0.9226555228233337), ('分手', 0.9135688543319702), ('距離', 0.880342423915863), ('男友', 0.8786644339561462), ('找個', 0.8754839897155762), ('擔心', 0.8725529313087463), ('吵架', 0.8680383563041687), ('爸媽', 0.8625649213790894), ('兩個', 0.8591646552085876), ('不想', 0.8558708429336548), ('我要', 0.853802502155304), ('我怕', 0.8512692451477051), ('分開', 0.8507095575332642), ('老婆', 0.844429075717926)]
+++++++++++++++++++++++++++++++++++
關鍵詞: 家人
[('做好', 0.964654803276062), ('房子', 0.9459130167961121), ('掙錢', 0.9400242567062378), ('分開', 0.9261205196380615), ('爸媽', 0.9220873117446899), ('有錢', 0.9190271496772766), ('子女', 0.9171360731124878), ('壓力', 0.9167039394378662), ('辦法', 0.9156253337860107), ('懂事', 0.9149639010429382), ('打拼', 0.9143495559692383), ('談過', 0.9131268858909607), ('依靠', 0.9117845892906189), ('談戀愛', 0.9093905687332153), ('留在', 0.9089971780776978)]
+++++++++++++++++++++++++++++++++++
關鍵詞: 長大
[('學會', 0.9459168910980225), ('身體', 0.9209215641021729), ('常常', 0.9176377058029175), ('懂事', 0.9148654937744141), ('適應', 0.9044305086135864), ('堅強', 0.9038822650909424), ('孩子', 0.9017991423606873), ('掙錢', 0.898858904838562), ('羨慕', 0.8973740935325623), ('年輕', 0.8969836235046387), ('房子', 0.8969626426696777), ('談戀愛', 0.8935214877128601), ('模樣', 0.8843299150466919), ('過得', 0.8807798624038696), ('保護', 0.8800650835037231)]
+++++++++++++++++++++++++++++++++++
關鍵詞: 味道
[('房間', 0.9597378969192505), ('調皮', 0.957197904586792), ('嘴裡', 0.9569690227508545), ('小孩子', 0.9566539525985718), ('陽臺', 0.9550118446350098), ('空氣', 0.9540750980377197), ('顯得', 0.9536328315734863), ('零食', 0.9528669118881226), ('時常', 0.9519882202148438), ('多愁善感', 0.9519380331039429), ('傷感', 0.9509293437004089), ('有種', 0.9501902461051941), ('一雙', 0.9479855298995972), ('韓劇', 0.9476990699768066), ('假裝', 0.946105420589447)]
+++++++++++++++++++++++++++++++++++
關鍵詞: 妹子
[('天秤座', 0.9551429748535156), ('典型', 0.9542213678359985), ('巨蟹座', 0.9520383477210999), ('處女座', 0.951753556728363), ('天蠍座', 0.9511485695838928), ('射手座', 0.9477106332778931), ('水瓶', 0.9455941915512085), ('水瓶座', 0.9437704682350159), ('160', 0.9407752156257629), ('白羊座', 0.937430202960968), ('雙子座', 0.934114933013916), ('星座', 0.9333192110061646), ('摩羯座', 0.9331715703010559), ('雙魚座', 0.9310780167579651), ('湖北', 0.9304903745651245)]
+++++++++++++++++++++++++++++++++++
複製程式碼
這回的 t-SNE 結果總算好了許多,看來訓練語料還是影響很大的,具體圖表裡詞語分佈就不過多講解了,可能圖上傳後也不太清晰,想看高清的SVG向量圖請到GitHub獲取: GitHub - DesertsX / JianShuJiaoYou
plot_tsne_2D(word_vectors, words_list)
複製程式碼
plot_tsne_3D(word_vectors, words_list)
複製程式碼
本文先更新到此,主要涉及關鍵詞的抽取、Word2Vec詞向量的嘗試和探索。後續LDA主題模型及主題的視覺化、文章照片爬取、人臉識別及顏值打分和照片牆等等更新後也會開源在GitHub - DesertsX / JianShuJiaoYou,歡迎star與指正。
系列文章:
亂燉資料之2700餘篇“簡書交友”專題文章資料的花式玩法
亂燉“簡書交友”資料之程式碼(1)
PS:預告下,即將開啟“Kaggle Kernel 學習系列”,GitHub - DesertsX / Kaggle-Kernel-Learning,歡迎star。
PPS:歡迎關注公眾號:牛衣古柳(ID:Deserts-X),以及歡迎加QQ群:Python交友娛樂會所(613176398)哈。娛樂會所,沒有嫩模。