聚类常规方法,分一下几步:
第一部分内容,本人暂不祥说,核心的内容,大概如下把
for line in file.readlines():
words = jieba.cut(line)
for word in words:
# print(word)
if word not in stopword:
output.write(word + " ")
接下来是将上述处理过的文档,进行向量化,此处,我选择的是doc2vec,即是document to vector,文档到向量,这个内容涉及内容也比较多,原理也可以不用了解的那么深,会用就可以了,也没有什么关系,
# doc2vec
#训练并保存模型
def open_file():
corpus = []
token_path = "res_title_news.txt"
try:
with open(token_path, 'r', encoding="utf-8") as t:
for line in t.readlines():
corpus.append(line.strip())
import gensim
sentences = gensim.models.doc2vec.TaggedLineDocument(token_path)
model = gensim.models.Doc2Vec(sentences, dm=1, size=200, window=10)
model.train(sentences, total_examples=model.corpus_count, epochs=100)
model.save('res_title_news_w2c.txt')
out = open('res_title_news_vector.txt', 'w')
for idx, docvec in enumerate(model.docvecs):
for value in docvec:
out.write(str(value) + ' ')
out.write('\n')
except Exception as e:
print(e)
open_file()
上面包含模型的训练与保存,会把当中文档向量的部分,放入到res_title_news_vector.txt中,打开这个文本文件之后,你会看到每一篇文档被训练成了200维度的向量。
那么模型训练好之后,接下来的是就是使用模型训练的向量,来完成Kmeans聚类,那么这个聚类是怎么做的尼?
import gensim
from gensim.models.doc2vec import Doc2Vec, LabeledSentence
def test_km():
model = gensim.models.Doc2Vec.load("res_title_news_vector.txt")#加载模型
from sklearn.cluster import KMeans
for k in range(5,20):
clf = KMeans(n_clusters=k, n_init=20, init='k-means++', n_jobs=4)#n_init选择质心的次数,返回最好的结果
s = clf.fit(model.docvecs)
# 20个中心点位置
# print(clf.cluster_centers_)
# 每个样本所属的簇,
print(clf.labels_)
i = 1
while i <= len(clf.labels_):
# print(i, clf.labels_[i - 1])
i = i + 1
# 每个点,到簇类中心的距离之和,用来评估簇的个数是否合适,距离越小说明簇分的越好,选取临界点的簇个数
print(clf.inertia_)
test_km()
这里我进行了多次K值的设定,想重上述的结果中,找到最好的结果。
结果表明当K=12时,效果较好。这个值是根据clf.inertia_(即簇内平方和SSE,每一个样本点到簇中心的距离之和)来确定,即手肘法(此部分,来自实验室成员所写:手肘法的核心思想是:随着聚类数k的增大,样本划分会更加精细,每个簇的聚合程度会逐渐提高,那么误差平方和SSE自然会逐渐变小。并且,当k小于真实聚类数时,由于k的增大会大幅增加每个簇的聚合程度,故SSE的下降幅度会很大,而当k到达真实聚类数时,再增加k所得到的聚合程度回报会迅速变小,所以SSE的下降幅度会骤减,然后随着k值的继续增大而趋于平缓,也就是说SSE和k的关系图是一个手肘的形状,而这个肘部对应的k值就是数据的真实聚类数。当然,这也是该方法被称为手肘法的原因。)
[ 3 8 13 13 11 6 13 0 0 5 3 1 5 13 6 0 0 12 4 15 12 6 1 9 7
8 8 6 7 12 4 11 11 4 3 15 0 0 5 3 5 4 12 1 4 12 11 10 12 13
12 4 15 4 4 8 11 0 0 5 3 6 11 11 4 4 13 11 13 0 4 10 4 2 2
3 3 13 4 4 2 15 12 12 15 9 13 8 3 0 12 6 3 2 0 15 11 2 12 15
2 8 15 15 15 13 4 10 4 3 3 2 14 12 13 12 4 13 5 5 4 14 3 1 12
4 1 4 2 3 11 13 2 4 12 6 6 1 1 2 6 11 12 13 13 2 15 11 9 11
11 15 5 1 15 15 12 15 12 13 15 11 15 11 11 3 15 11 12 15 11 15 5 15 15
15 15 15 15 11 15 15 5 15 15 15 15 1 15 14 14 14 14 14 14 14 14 14 14 14
14 14 14 13 14 0 14 6 14 14 6 8 7 6 6 0 14 7 8 6 7 0 14 4 6
7 0 7 7 6 8 6 3 3 0 2 2 8 8 3 3 6 0 6 0]
得到上述聚类结果后,依然看不出到底聚类效果怎么样,是否把同一主题的文本聚成一类,那么为了方便分析聚类结果,我们将文本所属簇与文本内容,一起展示出来,一探究竟,看看具体属于哪一类?
我们将此拼接成一个【K, text】形式,K即是文本所属的簇,text即是文本;
我们借用以下方法,此处是我测试的一个文本量很小的例子:输出结果是从小到大进行排序的,根据K值进行排序;
import numpy as np
x=np.array([1,0,0,2,2,0])
file = open('cute.txt','r', encoding='utf-8')
data = file.readlines()#同样是一个列表
# print(data[3])
index = x.argsort()#根据指针对x排序,[1,2,5,0,3,4]
print(index)
for i in range(len(index)):
print(x[index[i]], data[index[i]])
前面的整数是聚类的结果,后面是对应的文本,这样便于获取当前聚类的主题。
当我们获取到每一个簇中的文本,我们可以根据NLP技术,分析每一个簇的主题,或者是根据TFIDF方法,获取每个簇的关键词,根据关键词,进行主题的呈现。
下一章,我将继续写初始化质心的内容,如何设定Kmeans的初始化质心,以提升聚类效果和聚类性能!