Python使用K-means實(shí)現(xiàn)文本聚類功能
前言
最近遇到了這樣一個(gè)需求,將N個(gè)文本內(nèi)容聚類成若干個(gè)主題詞團(tuán),減少人工分析文本和分類文本的工作量。
實(shí)現(xiàn)思路是使用 K-means
算法通過高頻詞對(duì)文本內(nèi)容進(jìn)行聚類,K-means
算法實(shí)現(xiàn)原理簡(jiǎn)單易于理解,缺點(diǎn)是詞與詞之間的順序性和相互關(guān)系不能在分類中得到體現(xiàn)。實(shí)現(xiàn)步驟如下:
- 使用
jieba
對(duì)文本內(nèi)容進(jìn)行分詞處理; - 去掉停用詞;
- 使用
TF-IDF
算法將上一步過濾后的分詞列表轉(zhuǎn)換成矩陣形式; - 使用
K-means
聚類算法對(duì)矩陣計(jì)算相似性; - 獲取每個(gè)聚類的主題詞/詞團(tuán);
準(zhǔn)備樣本
周杰倫的30首歌曲的歌詞金句作為我們聚類樣本的內(nèi)容,保存到 sourceData/周杰倫.txt
文本中。
分詞
使用 python
的 pip
安裝結(jié)巴分詞組件
pip install jieba
定義一個(gè)函數(shù)方法,讀取 周杰倫.txt
文件,并對(duì)文件內(nèi)容的每一行文本做分詞處理。
import jieba def get_jiebaword(): try: with open('sourceData/周杰倫.txt', "r", encoding='utf-8') as fr: lines = fr.readlines() except FileNotFoundError: print("找不到此文件") jiebaword = [] for line in lines: line = line.strip('\n') # 清除多余的空格 line = "".join(line.split()) # 默認(rèn)精確模式 seg_list = jieba.cut(line, cut_all=False) word = "/".join(seg_list) jiebaword.append(word) return jiebaword
分詞后的文本列表,打印出來如圖所示:
停用詞
停用詞是一些沒有具體含義但在文本中經(jīng)常會(huì)出現(xiàn)的詞語,例如“的”、“是”、“許多”、“不僅”等。
中文停用詞我們可以去網(wǎng)上下載,地址如下:
https://gitcode.com/open-source-toolkit/63e0e/overview
下載后的停用詞在一個(gè) hit_stopwords.txt
文件中,如圖所示:
停用詞不只是只有文字,也包括一些標(biāo)點(diǎn)符號(hào)。
定義一個(gè)函數(shù)方法讀取停用詞。
def get_stopword(): stopword = [] try: with open('sourceData/hit_stopwords.txt', "r", encoding='utf-8') as fr: lines = fr.readlines() except FileNotFoundError: print("找不到此文件") for line in lines: line = line.strip('\n') stopword.append(line) return stopword
定義一個(gè)函數(shù)方法從樣本分詞列表中過濾掉停用詞,過濾后的結(jié)果保存到 CleanWords.txt
文件中。
def clean_stopword(jiebaword, stopword): fw = open('resultData/周杰倫/CleanWords.txt', 'a+', encoding='utf-8') for words in jiebaword: words = words.split('/') for word in words: if word not in stopword: fw.write(word + '\t') fw.write('\n') fw.close()
CleanWords.txt
文件如圖所示。
如果發(fā)現(xiàn)CleanWords.txt
文件中還有一些詞語會(huì)影響聚類的效果,可以使用如下語句添加停用詞。
for i in range(30): stopword.append(str(i+1)) stopword.append('一路') stopword.append('向北')
TF-IDF算法
為了讓計(jì)算機(jī)能夠理解詞語的相似度,我們可以將文本格式的數(shù)據(jù)轉(zhuǎn)換成矩陣類型的數(shù)據(jù), TF-IDF
矩陣在這方面是應(yīng)用最為廣泛的。
TF-IDF(Term Frequency-Inverse Document Frequency,詞頻-逆文檔頻率)
是一種在信息檢索和文本挖掘領(lǐng)域廣泛使用的統(tǒng)計(jì)方法,用于評(píng)估一個(gè)詞在文檔或語料庫(kù)中的重要程度。
TF
詞頻,表示某個(gè)詞在文檔中出現(xiàn)的頻率。詞頻反映了詞語在文檔中的重要性,出現(xiàn)次數(shù)越多,TF值越高。計(jì)算公式:
IDF
逆文檔頻率,表示某個(gè)詞在整個(gè)文檔集合中的稀有程度。逆文檔頻率反映了詞語在整個(gè)文檔集合中的普遍性,出現(xiàn)次數(shù)越多的詞,IDF值越低;反之,則越高。計(jì)算公式:
包含詞t的文檔書 +1
是為了防止除以 0
導(dǎo)致溢出。
總結(jié)一下 TF-IDF
, TF
表示相同的詞在兩篇文章中出現(xiàn)的頻次越高,兩篇文章越相似; IDF
表示某個(gè)詞在所有文本中出現(xiàn)次數(shù)較少,只在某兩篇文章中出現(xiàn)幾次,則該兩篇文章具有較高相似度。
scikit-learn
已經(jīng)實(shí)現(xiàn)了 TF-IDF
算法,我們首先要安裝scikit-learn
組件。
pip install scikit-learn
使用python
實(shí)現(xiàn),定義一個(gè)函數(shù)方法生成 TF-IDF
矩陣。
from sklearn.feature_extraction.text import TfidfVectorizer def get_tfidf(): try: with open('resultData/周杰倫/CleanWords.txt', "r", encoding='utf-8') as fr: lines = fr.readlines() except FileNotFoundError: print("找不到此文件") transformer = TfidfVectorizer() tfidf = transformer.fit_transform(lines) # 轉(zhuǎn)為數(shù)組形式 tfidf_arr = tfidf.toarray() return tfidf_arr
打印輸出的矩陣,如下圖所示:
這個(gè)矩陣的形狀是 30 * 217
,它表示 217
個(gè)分詞在 30
個(gè)文本中的 TF-IDF
值,值為0表示在此文章中沒有出現(xiàn)過。由于打印的不是完整的矩陣,所以上圖中的矩陣沒有將非0的值顯示出來。
K-means聚類
K-Means
聚類是一種常用的無監(jiān)督學(xué)習(xí)算法,用于將數(shù)據(jù)集分成K個(gè)簇(cluster),使得簇內(nèi)的數(shù)據(jù)點(diǎn)彼此之間盡可能相似,而簇間的數(shù)據(jù)點(diǎn)盡可能不同。 K-Means
算法的目標(biāo)是最小化簇內(nèi)數(shù)據(jù)點(diǎn)到簇中心的距離之和。
我們需要使用 nltk
組件調(diào)用 K-Means
算法。
pip install nltk
定義一個(gè)函數(shù)方法,獲取K-Means
聚類。
from nltk.cluster import KMeansClusterer, cosine_distance import pandas as pd def get_cluster(tfidf_arr, k): kmeans = KMeansClusterer(num_means=k, distance=cosine_distance, avoid_empty_clusters=True) # 分成k類,使用余弦相似分析 kmeans.cluster(tfidf_arr) # 獲取分類 kinds = pd.Series([kmeans.classify(i) for i in tfidf_arr]) fw = open('resultData/周杰倫/ClusterText.txt', 'a+', encoding='utf-8') for i, v in kinds.items(): fw.write(str(i) + '\t' + str(v) + '\n') fw.close()
聚類結(jié)果保存在 ClusterText.txt
文件中,結(jié)果如圖所示:
圖中有兩列數(shù)字,第一列數(shù)字是從0到29按順序排列的數(shù)字,表示30個(gè)文本的序號(hào)。第二列數(shù)字表示5個(gè)聚類的序號(hào) 0~4
。
獲取主題詞
前面幾步已經(jīng)得到了對(duì)周杰倫歌詞的聚類索引,但是我們并不清楚這些聚類索引代表什么含義,所以我們可以將這5個(gè)聚類里詞頻最高的幾個(gè)詞給提取出來。
定義一個(gè)函數(shù)方法,獲取分類文檔。
def cluster_text(text_cnt): index_cluser = [] try: with open('resultData/周杰倫/ClusterText.txt', "r", encoding='utf-8') as fr: lines = fr.readlines() except FileNotFoundError: print("找不到此文件") for line in lines: line = line.strip('\n') line = line.split('\t') index_cluser.append(line) # index_cluser[i][j]表示第i行第j列 try: with open('resultData/周杰倫/CleanWords.txt', "r", encoding='utf-8') as fr: lines = fr.readlines() except FileNotFoundError: print("找不到此文件") for index, line in enumerate(lines): for i in range(text_cnt): if str(index) == index_cluser[i][0]: fw = open('resultData/周杰倫/cluster' + index_cluser[i][1] + '.txt', 'a+', encoding='utf-8') fw.write(line) fw.close()
將30個(gè)歌詞文本的聚類結(jié)果分別放入5個(gè)文件中。
其中一個(gè)cluster文件結(jié)果如下:
得到以上分類文檔以后,再分別統(tǒng)計(jì)各個(gè)聚類中頻次最高的幾個(gè)詞,定義一個(gè)函數(shù)方法,代碼如下:
from collections import Counter def get_title(cluster, top_n=5): fw = open('resultData/周杰倫/title.txt', 'a+', encoding='utf-8') for i in range(cluster): try: with open('resultData/周杰倫/cluster' + str(i) + '.txt', "r", encoding='utf-8') as fr: lines = fr.readlines() except FileNotFoundError: print("找不到此文件") all_words = [] for line in lines: line = line.strip('\n') line = line.split('\t') for word in line: all_words.append(word) c = Counter() for x in all_words: if len(x) > 1 and x != '\r\n': c[x] += 1 print('主題' + str(i) + '----------------------------------------------------\n詞頻統(tǒng)計(jì)結(jié)果:\n') fw.write('主題' + str(i) + '----------------------------------------------------\n詞頻統(tǒng)計(jì)結(jié)果:\n') # 輸出詞頻最高的那個(gè)詞,也可以輸出多個(gè)高頻詞 for (k, v) in c.most_common(top_n): print(k, ':', v, '\n') fw.write(k + ':' + str(v) + '\n') fw.write('\n') fw.close()
執(zhí)行結(jié)果保存在 title.txt
文件中,我這里參數(shù) top_n
是傳的3,表示獲取3個(gè)主題詞,效果如圖所示:
因?yàn)闃颖咀龅谋容^少,所以詞頻統(tǒng)計(jì)的數(shù)量不多,所以代表性也不是很強(qiáng)。另一個(gè)原因是 K-means
算法是一種無監(jiān)督算法,一開始要定義好聚類的數(shù)量,算法根據(jù)聚類的數(shù)量隨機(jī)選取聚類中心點(diǎn),中心點(diǎn)選的不準(zhǔn)會(huì)極大影響聚類結(jié)果的準(zhǔn)確度。所以可以定義不同的聚類數(shù)量多計(jì)算幾次,直到滿意為止。
主流程方法
主流程 main
方法基本是調(diào)用上文中列表的所有函數(shù)方法,按步驟開始執(zhí)行。
此外,還定義了一個(gè) delete_files_in_directory
函數(shù)用來在生成聚類結(jié)果之前先刪除上一次生成的結(jié)果,否則生成的結(jié)果txt文件會(huì)疊加上一次的結(jié)果。
import jieba from sklearn.feature_extraction.text import TfidfVectorizer from nltk.cluster import KMeansClusterer, cosine_distance import pandas as pd from collections import Counter import os def delete_files_in_directory(directory): if not os.path.exists(directory): os.mkdir(directory) return # 遍歷目錄中的所有文件 for filename in os.listdir(directory): file_path = os.path.join(directory, filename) # 檢查路徑是否為文件(而非子目錄等) if os.path.isfile(file_path): # 刪除文件 os.remove(file_path) if __name__ == '__main__': # 定義聚類的個(gè)數(shù) cluster = 5 # 定義主題詞個(gè)數(shù) top_n = 3 # 刪除上一次的結(jié)果數(shù)據(jù) delete_files_in_directory('resultData/周杰倫') # 結(jié)巴分詞 jiebaword = get_jiebaword() # 獲取停用詞 stopword = get_stopword() # ---停用詞補(bǔ)充,視具體情況而定--- for i in range(30): stopword.append(str(i+1)) stopword.append('一路') stopword.append('向北') # ---------------------- # 去除停用詞 clean_stopword(jiebaword, stopword) # 獲取tfidf矩陣 tfidf_arr = get_tfidf() text_cnt = tfidf_arr.shape[0] # ---輸出測(cè)試--- # print(tfidf_arr) # print(tfidf_arr.shape) # ------------- # K-means聚類 get_cluster(tfidf_arr, cluster) # 獲取分類文件 cluster_text(text_cnt) # 統(tǒng)計(jì)出主題詞 get_title(cluster, top_n)
以上就是Python使用K-means實(shí)現(xiàn)文本聚類功能的詳細(xì)內(nèi)容,更多關(guān)于Python K-means文本聚類的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python多線程批量采集圖片的代碼實(shí)現(xiàn)
這篇文章主要給大家介紹了Python多線程批量采集圖片的代碼實(shí)現(xiàn),文中通過代碼示例講解的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2024-05-05Python實(shí)現(xiàn)的列表排序、反轉(zhuǎn)操作示例
這篇文章主要介紹了Python實(shí)現(xiàn)的列表排序、反轉(zhuǎn)操作,結(jié)合實(shí)例形式分析了Python針對(duì)列表的sort排序、以及基于reverse、切片的反轉(zhuǎn)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-03-03python OpenCV實(shí)現(xiàn)答題卡識(shí)別判卷
這篇文章主要為大家詳細(xì)介紹了python OpenCV實(shí)現(xiàn)答題卡識(shí)別判卷,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06教你用Type Hint提高Python程序開發(fā)效率
本文通過介紹和實(shí)例教大家如何利用Type Hint來提升Python程序開發(fā)效率,對(duì)大家使用python開發(fā)很有幫助,有需要的參考學(xué)習(xí)。2016-08-08cython加速python代碼的方法實(shí)現(xiàn)
本文主要介紹了cython加速python代碼的方法實(shí)現(xiàn),特別是在涉及到數(shù)值計(jì)算密集型任務(wù)時(shí),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07Python開發(fā)的HTTP庫(kù)requests詳解
Requests是用Python語言編寫,基于urllib,采用Apache2 Licensed開源協(xié)議的HTTP庫(kù)。它比urllib更加方便,可以節(jié)約我們大量的工作,完全滿足HTTP測(cè)試需求。Requests的哲學(xué)是以PEP 20 的習(xí)語為中心開發(fā)的,所以它比urllib更加Pythoner。更重要的一點(diǎn)是它支持Python3哦!2017-08-08Python?Cloudinary實(shí)現(xiàn)圖像和視頻上傳詳解
這篇文章主要介紹了Python?Cloudinary實(shí)現(xiàn)圖像和視頻上傳功能,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-11-11Python隊(duì)列RabbitMQ 使用方法實(shí)例記錄
這篇文章主要介紹了Python隊(duì)列RabbitMQ 使用方法,結(jié)合實(shí)例形式分析了Python隊(duì)列RabbitMQ創(chuàng)建隊(duì)列發(fā)送消息與創(chuàng)建消費(fèi)者消費(fèi)信息相關(guān)操作技巧,需要的朋友可以參考下2019-08-08Python+OpenCV實(shí)現(xiàn)尋找到圓點(diǎn)標(biāo)定板的角點(diǎn)
這篇文章主要為大家詳細(xì)介紹了Python+OpenCV實(shí)現(xiàn)找到圓點(diǎn)標(biāo)定板所有點(diǎn)后通過距離找兩個(gè)角點(diǎn),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-11-11