點(diǎn)擊查看原文
對(duì)于無(wú)監(jiān)督學(xué)習(xí)來(lái)說(shuō)综芥,聚類(lèi)算法對(duì)于數(shù)據(jù)挖掘牵囤、NLP處理等方向都有著非常重要的地位斗塘。常見(jiàn)的聚類(lèi)算法比如K-means、BIRCH(Balanced Iterative Reducing and Clustering Using Hierarchies)止剖、GMM(Gaussian mixture model)腺阳、GAAC(Group-average Agglomerative Clustering)等,但是用得最普遍的還是K-means算法穿香,其時(shí)間復(fù)雜度低且實(shí)現(xiàn)的效果較好受到廣泛的應(yīng)用亭引。
本文代碼的相關(guān)環(huán)境為:
- python3以上
- sklearn 機(jī)器學(xué)習(xí)常用包
- jieba 中文分詞
- matplotlib 可視化
準(zhǔn)備語(yǔ)料
語(yǔ)料格式為每行表示一個(gè)文檔(語(yǔ)句、文章等需要聚類(lèi)的文本)皮获,行數(shù)表示需要聚類(lèi)的所有文本焙蚓。
類(lèi)似這樣的:
導(dǎo)入相關(guān)包
from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer
from sklearn.manifold import TSNE
from sklearn.cluster import KMeans
from data_utils import *
import jieba
import matplotlib.pyplot as plt
加載語(yǔ)料
# bigram分詞
segment_bigram = lambda text: " ".join([word + text[idx + 1] for idx, word in enumerate(text) if idx < len(text) - 1])
# 結(jié)巴中文分詞
segment_jieba = lambda text: " ".join(jieba.cut(text))
'''
1、加載語(yǔ)料
'''
corpus = []
with open("sanhu.txt", "r", encoding="utf-8") as f:
for line in f:
# 去掉標(biāo)點(diǎn)符號(hào)
corpus.append(segment_jieba(remove_punc(line.strip())))
'''
代碼中定義了兩種分詞方式,一種是單純的使用bi-gram分詞购公,一種是使用jieba進(jìn)行中文分詞萌京,兩份分詞方式根據(jù)效果自己選擇使用哪種。加載語(yǔ)料的時(shí)候把標(biāo)點(diǎn)符號(hào)去掉宏浩,這對(duì)于文本聚類(lèi)幾乎沒(méi)有作用知残。還可以去掉自己定義的一些類(lèi)似“你”、“我”比庄、“他”等大量口語(yǔ)化中均會(huì)出現(xiàn)的停止詞求妹,這類(lèi)詞語(yǔ)往往對(duì)聚類(lèi)也起不到作用。
計(jì)算TF-IDF權(quán)重
'''
2佳窑、計(jì)算tf-idf設(shè)為權(quán)重
'''
vectorizer = CountVectorizer()
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))
'''
3制恍、獲取詞袋模型中的所有詞語(yǔ)特征
如果特征數(shù)量非常多的情況下可以按照權(quán)重降維
'''
word = vectorizer.get_feature_names()
print("word feature length: {}".format(len(word)))
'''
4、導(dǎo)出權(quán)重神凑,到這邊就實(shí)現(xiàn)了將文字向量化的過(guò)程净神,矩陣中的每一行就是一個(gè)文檔的向量表示
'''
tfidf_weight = tfidf.toarray()
關(guān)于TF-IDF網(wǎng)上有很多教程都有詳細(xì)的解釋。這里解釋下為什么用這個(gè)值作為權(quán)重耙厚。
將文本向量化的方式其實(shí)有很多强挫,最簡(jiǎn)單的就是one-hot方式,在之前的文章中也講過(guò)這種方式的實(shí)現(xiàn)原理薛躬,如果不用TF-IDF設(shè)置權(quán)重,那么呆细,后面進(jìn)行文本向量化之后的矩陣值只有0型宝、1兩種,詞與詞之間的權(quán)重沒(méi)有進(jìn)行區(qū)分絮爷,所以用這種方式設(shè)置權(quán)重趴酣。
文本聚類(lèi)
'''
5、對(duì)向量進(jìn)行聚類(lèi)
'''
# 指定分成7個(gè)類(lèi)
kmeans = KMeans(n_clusters=7)
kmeans.fit(tfidf_weight)
# 打印出各個(gè)族的中心點(diǎn)
print(kmeans.cluster_centers_)
for index, label in enumerate(kmeans.labels_, 1):
print("index: {}, label: {}".format(index, label))
# 樣本距其最近的聚類(lèi)中心的平方距離之和坑夯,用來(lái)評(píng)判分類(lèi)的準(zhǔn)確度岖寞,值越小越好
# k-means的超參數(shù)n_clusters可以通過(guò)該值來(lái)評(píng)估
print("inertia: {}".format(kmeans.inertia_))
k-means的缺陷之一就是需要自己指定需要分類(lèi)的族數(shù),也就是代碼中的n_clusters
柜蜈,選擇超參數(shù)的過(guò)程中仗谆,可以使用kmeans.inertia_
值作為評(píng)估標(biāo)準(zhǔn),其值越小越好淑履。
可視化
'''
6隶垮、可視化
'''
# 使用T-SNE算法,對(duì)權(quán)重進(jìn)行降維秘噪,準(zhǔn)確度比PCA算法高狸吞,但是耗時(shí)長(zhǎng)
tsne = TSNE(n_components=2)
decomposition_data = tsne.fit_transform(tfidf_weight)
x = []
y = []
for i in decomposition_data:
x.append(i[0])
y.append(i[1])
fig = plt.figure(figsize=(10, 10))
ax = plt.axes()
plt.scatter(x, y, c=kmeans.labels_, marker="x")
plt.xticks(())
plt.yticks(())
# plt.show()
plt.savefig('./sample.png', aspect=1)
前面將文本向量化之后,每個(gè)文檔的維度非常高,進(jìn)行可視化之前需要對(duì)其降維蹋偏,降維算法也有很多便斥,這里使用T-SNE算法,其優(yōu)點(diǎn)就是準(zhǔn)確度比較高威始,但是耗時(shí)比較長(zhǎng)枢纠,如果接受不了耗時(shí)長(zhǎng),可以使用PCA算法字逗。
對(duì)降維后的數(shù)據(jù)decomposition_data
用plt進(jìn)行可視化京郑。