Python使用K-means實現(xiàn)文本聚類功能
前言
最近遇到了這樣一個需求,將N個文本內(nèi)容聚類成若干個主題詞團,減少人工分析文本和分類文本的工作量。
實現(xiàn)思路是使用 K-means算法通過高頻詞對文本內(nèi)容進行聚類,K-means算法實現(xiàn)原理簡單易于理解,缺點是詞與詞之間的順序性和相互關(guān)系不能在分類中得到體現(xiàn)。實現(xiàn)步驟如下:
- 使用
jieba對文本內(nèi)容進行分詞處理; - 去掉停用詞;
- 使用
TF-IDF算法將上一步過濾后的分詞列表轉(zhuǎn)換成矩陣形式; - 使用
K-means聚類算法對矩陣計算相似性; - 獲取每個聚類的主題詞/詞團;
準(zhǔn)備樣本
周杰倫的30首歌曲的歌詞金句作為我們聚類樣本的內(nèi)容,保存到 sourceData/周杰倫.txt 文本中。

分詞
使用 python的 pip安裝結(jié)巴分詞組件
pip install jieba
定義一個函數(shù)方法,讀取 周杰倫.txt文件,并對文件內(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)常會出現(xiàn)的詞語,例如“的”、“是”、“許多”、“不僅”等。
中文停用詞我們可以去網(wǎng)上下載,地址如下:
https://gitcode.com/open-source-toolkit/63e0e/overview
下載后的停用詞在一個 hit_stopwords.txt 文件中,如圖所示:

停用詞不只是只有文字,也包括一些標(biāo)點符號。
定義一個函數(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
定義一個函數(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 文件中還有一些詞語會影響聚類的效果,可以使用如下語句添加停用詞。
for i in range(30):
stopword.append(str(i+1))
stopword.append('一路')
stopword.append('向北')
TF-IDF算法
為了讓計算機能夠理解詞語的相似度,我們可以將文本格式的數(shù)據(jù)轉(zhuǎn)換成矩陣類型的數(shù)據(jù), TF-IDF矩陣在這方面是應(yīng)用最為廣泛的。
TF-IDF(Term Frequency-Inverse Document Frequency,詞頻-逆文檔頻率)是一種在信息檢索和文本挖掘領(lǐng)域廣泛使用的統(tǒng)計方法,用于評估一個詞在文檔或語料庫中的重要程度。
TF詞頻,表示某個詞在文檔中出現(xiàn)的頻率。詞頻反映了詞語在文檔中的重要性,出現(xiàn)次數(shù)越多,TF值越高。計算公式:

IDF逆文檔頻率,表示某個詞在整個文檔集合中的稀有程度。逆文檔頻率反映了詞語在整個文檔集合中的普遍性,出現(xiàn)次數(shù)越多的詞,IDF值越低;反之,則越高。計算公式:

包含詞t的文檔書 +1 是為了防止除以 0 導(dǎo)致溢出。
總結(jié)一下 TF-IDF , TF 表示相同的詞在兩篇文章中出現(xiàn)的頻次越高,兩篇文章越相似; IDF 表示某個詞在所有文本中出現(xiàn)次數(shù)較少,只在某兩篇文章中出現(xiàn)幾次,則該兩篇文章具有較高相似度。
scikit-learn 已經(jīng)實現(xiàn)了 TF-IDF 算法,我們首先要安裝scikit-learn 組件。
pip install scikit-learn
使用python 實現(xiàn),定義一個函數(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
打印輸出的矩陣,如下圖所示:

這個矩陣的形狀是 30 * 217 ,它表示 217 個分詞在 30 個文本中的 TF-IDF 值,值為0表示在此文章中沒有出現(xiàn)過。由于打印的不是完整的矩陣,所以上圖中的矩陣沒有將非0的值顯示出來。
K-means聚類
K-Means 聚類是一種常用的無監(jiān)督學(xué)習(xí)算法,用于將數(shù)據(jù)集分成K個簇(cluster),使得簇內(nèi)的數(shù)據(jù)點彼此之間盡可能相似,而簇間的數(shù)據(jù)點盡可能不同。 K-Means 算法的目標(biāo)是最小化簇內(nèi)數(shù)據(jù)點到簇中心的距離之和。
我們需要使用 nltk 組件調(diào)用 K-Means 算法。
pip install nltk
定義一個函數(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個文本的序號。第二列數(shù)字表示5個聚類的序號 0~4。
獲取主題詞
前面幾步已經(jīng)得到了對周杰倫歌詞的聚類索引,但是我們并不清楚這些聚類索引代表什么含義,所以我們可以將這5個聚類里詞頻最高的幾個詞給提取出來。
定義一個函數(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個歌詞文本的聚類結(jié)果分別放入5個文件中。

其中一個cluster文件結(jié)果如下:

得到以上分類文檔以后,再分別統(tǒng)計各個聚類中頻次最高的幾個詞,定義一個函數(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)計結(jié)果:\n')
fw.write('主題' + str(i) + '----------------------------------------------------\n詞頻統(tǒng)計結(jié)果:\n')
# 輸出詞頻最高的那個詞,也可以輸出多個高頻詞
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個主題詞,效果如圖所示:

因為樣本做的比較少,所以詞頻統(tǒng)計的數(shù)量不多,所以代表性也不是很強。另一個原因是 K-means 算法是一種無監(jiān)督算法,一開始要定義好聚類的數(shù)量,算法根據(jù)聚類的數(shù)量隨機選取聚類中心點,中心點選的不準(zhǔn)會極大影響聚類結(jié)果的準(zhǔn)確度。所以可以定義不同的聚類數(shù)量多計算幾次,直到滿意為止。
主流程方法
主流程 main 方法基本是調(diào)用上文中列表的所有函數(shù)方法,按步驟開始執(zhí)行。
此外,還定義了一個 delete_files_in_directory 函數(shù)用來在生成聚類結(jié)果之前先刪除上一次生成的結(jié)果,否則生成的結(jié)果txt文件會疊加上一次的結(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__':
# 定義聚類的個數(shù)
cluster = 5
# 定義主題詞個數(shù)
top_n = 3
# 刪除上一次的結(jié)果數(shù)據(jù)
delete_files_in_directory('resultData/周杰倫')
# 結(jié)巴分詞
jiebaword = get_jiebaword()
# 獲取停用詞
stopword = get_stopword()
# ---停用詞補充,視具體情況而定---
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]
# ---輸出測試---
# print(tfidf_arr)
# print(tfidf_arr.shape)
# -------------
# K-means聚類
get_cluster(tfidf_arr, cluster)
# 獲取分類文件
cluster_text(text_cnt)
# 統(tǒng)計出主題詞
get_title(cluster, top_n)
以上就是Python使用K-means實現(xiàn)文本聚類功能的詳細(xì)內(nèi)容,更多關(guān)于Python K-means文本聚類的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python操作PostgreSQL數(shù)據(jù)庫的基本方法(增刪改查)
PostgreSQL數(shù)據(jù)庫是最常用的關(guān)系型數(shù)據(jù)庫之一,最吸引人的一點是它作為開源數(shù)據(jù)庫且具有可拓展性,能夠提供豐富的應(yīng)用,這篇文章主要給大家介紹了關(guān)于Python操作PostgreSQL數(shù)據(jù)庫的基本方法,文中介紹了連接PostgreSQL數(shù)據(jù)庫,以及增刪改查,需要的朋友可以參考下2023-09-09
Python實現(xiàn)語音識別Whisper的使用示例
Whisper是由OpenAI基于Python開發(fā)的能夠識別多國語言的語音識別模型,本文主要介紹了Python實現(xiàn)語音識別Whisper的使用示例,具有一定的參考價值,感興趣的可以了解一下2023-12-12
react+django清除瀏覽器緩存的幾種方法小結(jié)
今天小編就為大家分享一篇react+django清除瀏覽器緩存的幾種方法小結(jié),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-07-07
Python數(shù)據(jù)處理利器Pandas?DataFrame常用操作
這篇文章主要為大家介紹了Python數(shù)據(jù)處理利器Pandas?DataFrame,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06

