當前位置:
首頁 > 新聞 > 利用 Doc2Vec對Quora 問題標籤聚類

利用 Doc2Vec對Quora 問題標籤聚類

  引言

Quora是一個流行的知識分享平台,我常常在Quora上分享我的想法。這個平台是基於問答的形式,它因其簡易的設計和平滑的用戶體驗而出名。

當新的問題被添加到Quora時,這些問題由機器人自動基於問題的上下文進行標記並稍後由用戶進行編輯。這些標籤反映了問題被歸入的話題類別。如下是一個問題的基本概貌。

最近我在尋找合適的數據集,然後我偶然看到了Quora里的一個這個頁面: Programming Challenges。我選擇了這個叫做Answered的二分類問題挑戰。其中,包括了近10000個問題(訓練集和測試集總計)。每個問題和其話題標籤以及其他的一些信息被以JSON格式儲存。下圖是一個JSON的示例。

示例問題JSON


  動手干吧

第一個任務就是要從JSON文件中讀取數據。訓練集總共大約有9000個問題,而測試集總共約1000個問題。

import json f = open("answered_data_10k.in").read().split("
")train_set = f[1:9001]test_set = f[9002:-1]train = [json.loads(i) for i in train_set]test = [json.loads(i) for i in test_set]questions = train + test

接下來就要提取出所有數據集中的主題標籤。在JSON文件中,主題存儲在鍵"key"中。不同的問題有不同數量的主題標籤。單個問題所允許存在的最大標籤數為26。同時也存在沒有關聯主題標籤的問題。

# Create the list of topics topic_list = []for question in questions:if len(question["topics"]) > 0:for topic in question["topics"]:topic_list = topic_list + [topic["name"]]topic_list = list(set(topic_list))print(len(topic_list))

在這個挑戰所提供的數據中,一共有8762個主題標籤。

在提取出主題標籤之後,我們需要將具有相同標籤的問題聚類。在動手之前,我們先對數據進行分析,因為如果直接對8762個進行聚類將會很困難而且聚類的質量也難以保證。

因此我們限定了每一個主題下的最小問題數來解決這個問題。擁有多於1個問題的主題有3275個。擁有5個問題的主題恰好有900個,這個數量相對更適合進行聚類。

最終,我們決定將主題下的最小問題數規定為5個,這主要有兩個原因。首先是為了更好地用向量來表示主題,其次因為具有較少問題的主題大多數情況下是和無關的問題所關聯的。

#Assigning question to topics.question_list = []final_topic_list = []for topic in topic_list:temp = []for question in questions:context = [i["name"] for i in question["topics"]]if topic in context:temp.append(question["question_text"]) if len(temp) >= 5:question_list.append(temp)final_topic_list.append(topic)topic_list = final_topic_list

接下來,我們寫一個函數,通過轉換為小寫、去除標點符號和停用詞來正則化每個段落。每個話題下有五到多個問題。我們把每個話題下的問題的集合當做一個文檔。

這樣,我們先遍歷話題標籤,然後把問題聚集成段落,再把段落正則化化。然後我們把段落和段落的話題標籤餵給Gensim的TaggedDocument函數,進行進一步的正則化。

from nltk import word_tokenizefrom nltk.corpus import stopwordsfrom gensim import modelsfrom gensim.models.doc2vec import TaggedDocument#Function for normalizing paragraphs.def normalize(string):lst = word_tokenize(string)lst =[word.lower() for word in lst if word.isalpha()]lst = [w for w in lst if not w in stopwords.words("english")]return(lst)# Aggregate questions under each topic tag as a paragraph. # Normalize the paragraph # Feed the normalized paragraph along with the topic tag into Gensim"s Tagged Document function. # Append the return value to docs.docs = []for index, item in enumerate(topic_list):question = " ".join(question_list[index])question = normalize(question)docs.append(TaggedDocument(words=question, tags=[item]))

為Gensim的DocVec準備數據

接下來我們訓練Doc2Vec模型。

應該調整vector_size和window,直到結果是最優的。

import gensimmodel = gensim.models.Doc2Vec(vector_size= 200, window= 3, min_count= 0, workers=4, epochs= 40)model.build_vocab(docs)model.train(docs, total_examples=model.corpus_count, epochs=model.iter)

Doc2Vec Training

Doc2Vec模型訓練好後,我們就用KMeans演算法聚類了文檔向量。簇的數量從100到50之間進行了檢查。接近100的簇數會導致大簇被切分成小簇,而簇數等於50時會使得沒有相關性的簇被組合成大簇。在仔細評估聚簇結果後,最後選擇60作為簇數。

from sklearn.cluster import KMeansfrom sklearn import metricsimport pylab as plimport matplotlib.pyplot as pltfrom sklearn.decomposition import PCAkmeans_model = KMeans(n_clusters= 60, init="k-means++", max_iter=100) X = kmeans_model.fit(model.docvecs.doctag_syn0)labels= kmeans_model.labels_.tolist()l = kmeans_model.fit_predict(model.docvecs.doctag_syn0)#map each centroid to its topic tagword_centroid_map = dict(zip( model.docvecs.offset2doctag, l))#Print Cluster Listfor cluster in range(0,100): print("
Cluster %d" % cluster)words = []for i in range(0,len(word_centroid_map.values())):if(list(word_centroid_map.values())[i] == cluster ):words.append(list(word_centroid_map.keys())[i])print(words)

擬合KMeans模型並取回簇的列表

......

想要繼續閱讀文章,並且查看該篇文章更多代碼、鏈接和參考文獻?


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 雷鋒網 的精彩文章:

ROOBO將於7月27日發布兒童智能平台「童秘」
賓大沃頓商學院新開設區塊鏈課程 瑞波幣提供部分支持

TAG:雷鋒網 |