热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

文本特征处理及文本聚类的几种方法

文本特征处理及文本聚类的几种方法本项目完整源码地址:https:github.comangeliababytextcluster项目博客地址:https:blog

文本特征处理及文本聚类的几种方法

本项目完整源码地址:
https://github.com/angeliababy/textcluster

项目博客地址:
https://blog.csdn.net/qq_29153321/article/details/104015257


数据准备


测试数据说明

data_offline文件夹包含200 economy 类,200个sports类,200个environment类,50个other类,为线下做试验的数据集,id2class.txt为data_offline文件夹中每个文件对应的类别,以此可以比较聚类效果。

src/get_data下为数据准备的过程,获取去除标点符号的文本及编号:

1.get_res.py为处理普通的txt文件

filelist = os.listdir(base_path)f2 = open(out_path, 'w', encoding='UTF-8')for files in filelist:# print (files)filename = files.split('.')[0]f = open(base_path + files, 'r', encoding='UTF-8')text = f.read().replace('\n', '')data = ''.join(re.findall(u'[\u4e00-\u9fff]+', text)) # 必须为unicode类型,取出所有中文字符f2.write(filename + ',')f2.write(data + '\n')f2.close()

2.get_res_csv.py为处理csv文件,并将繁体文转化为简体文

data = pd.read_csv(base_path, usecols=[0, 1, 2], encoding='UTF-8')data.columns = ["news_id", "title", "content"]# data = open(base_path, 'r', encoding='UTF-8')f2 = open(out_path, 'w', encoding='UTF-8')for i in range(len(data)):try:title = data["title"][i].replace('\n', '')#title = Converter('zh-hans').convert(title)title = ''.join(re.findall(u'[\u4e00-\u9fff]+', title))content =data["content"][i].replace('\n', '')content = ''.join(re.findall(u'[\u4e00-\u9fff]+', content))f2.write(str(np.squeeze(data.iloc[i, [0]].values)) + ',')f2.write(title+content + '\n')except:print(data.iloc[i,[0]].values)

文本特征处理

1.tf-idf:
tf-idf = tf(词频)*idf(逆词频)
其中idf(x) = log(N/N(x))
tfidf_Res.py:

# 一、获取标题和分词
sen_seg_list = []
title_list = []
flag, lines = self.load_processfile(process_file)
if flag == False:logging.error("load error")return False, "load error"
for line in lines:title_list.append(line.split(',')[0])sen_seg_list.append(self.seg_words(line.split(',')[1]))# 二、tf-idf提取特征
if not os.path.exists(tfidf_ResFileName):# 该类会将文本中的词语转换为词频矩阵,矩阵元素a[i][j] 表示j词在i类文本下的词频tf_vectorizer = CountVectorizer()# fit_transform是将文本转为词频矩阵tf_matrix = tf_vectorizer.fit_transform(sen_seg_list)# tf_weight = tf_matrix.toarray()# print(tf_weight)# 该类会统计每个词语的tf-idf权值tfidf_transformer = TfidfTransformer()# fit_transform是计算tf-idftfidf_matrix = tfidf_transformer.fit_transform(tf_matrix)# 获取词袋模型中的所有词语word_list = tf_vectorizer.get_feature_names()# 将tf-idf矩阵抽取出来,元素a[i][j]表示j词在i类文本中的tf-idf权重tfidf_weight = tfidf_matrix.toarray()

2.doc2vec
word2vec有2种算法:连续词袋模型(CBOW)和Skip-Gram模型。
CBOW:
在这里插入图片描述
Skip-Gram:
在这里插入图片描述
句向量,是 word2vec 的拓展,考虑了句子的序号id

# 一、获取标题和分词
sen_seg_list = []
title_list = []
flag, lines = self.load_processfile(process_file)
if flag == False:logging.error("load error")return False, "load error"
for line in lines:title_list.append(line.split(',')[0])sen_seg_list.append(self.seg_words(line.split(',')[1]))if not os.path.exists(modelpath):# 存储分词文本if not os.path.exists(data1):self.output_file(data1, sen_seg_list)print("success output")# doc2vec提取特征
sentences = gensim.models.doc2vec.TaggedLineDocument(data1)if not os.path.exists(modelpath):# doc2vec提取特征# 训练并保存模型model = gensim.models.Doc2Vec(sentences, size=100, window=2, min_count=3)model.train(sentences, total_examples=model.corpus_count, epochs=1000)model.save(modelpath)infered_vectors_list = []
print("load doc2vec model...")
model_dm = gensim.models.Doc2Vec.load(modelpath)
print("load train vectors...")
i = 0
for text, label in sentences:vector = model_dm.infer_vector(text)infered_vectors_list.append(vector)i += 1

3.lda
文档主题生成模型,词袋模型,完全考虑词语的分布来判断其主题分布,并依据每个文本的主题概率分布来进行聚类。LDA的目的就是要识别主题,即把文档—词汇矩阵变成文档—主题矩阵(分布)和主题—词汇矩阵(分布)

# 一、获取标题和分词
flag, lines = self.load_processfile(process_file)
if flag == False:logging.error("load error")return False, "load error"
# 分词结果与其他方法形式不同
title_list, sen_seg_list = self.seg_words(lines)# 二、lda模型提取特征
# 构造词典
dictionary = corpora.Dictionary(sen_seg_list)
# 基于词典,使【词】→【稀疏向量】,并将向量放入列表,形成【稀疏向量集】
corpus = [dictionary.doc2bow(words) for words in sen_seg_list]lda = models.ldamodel.LdaModel(corpus=corpus, id2word=dictionary, num_topics=15)lda.save('zhwiki_lda.model')
lda = models.ldamodel.LdaModel.load('zhwiki_lda.model')
# 打印所有主题,每个主题显示10个词
for topic in lda.print_topics(num_words=500):print(topic)# 主题矩阵
ldainfer = lda.inference(corpus)[0]

聚类分析

kmeans:
k簇中心,离簇中心最近进行聚类

k = evaluation(tfidf_matrix)
# 三、Kmeans,大数据量下用Mini-Batch-KMeans算法
km = KMeans(n_clusters=k)
km.fit(tfidf_matrix)
print(Counter(km.labels_)) # 打印每个类多少个
# print(km.cluster_centers_) # 中心点# 存储每个样本所属的簇
clusterRes = codecs.open(cluster_ResFileName, 'w', encoding='UTF-8')
count = 1
while count <&#61; len(km.labels_):clusterRes.write(str(title_list[count - 1]) &#43; &#39;\t&#39; &#43; str(km.labels_[count - 1]))clusterRes.write(&#39;\r\n&#39;)count &#61; count &#43; 1
clusterRes.close()

聚类个数选择&#xff1a;

# ### 三者选其一&#xff0c;SSE较好、但需要看拐点&#xff0c;轮廓系数法比较方便
# # 方法一&#xff1a;&#39;利用SSE选择k&#xff08;手肘法&#xff09;&#39;
# SSE &#61; [] # 存放每次结果的误差平方和
# for k in range(2, 5):
# km &#61; KMeans(n_clusters&#61;k) # 构造聚类器
# km.fit(tfidf_matrix)
# SSE.append(km.inertia_)
#
# X &#61; range(2, 5)
# plt.xlabel(&#39;k&#39;)
# plt.ylabel(&#39;SSE&#39;)
# plt.plot(X, SSE, &#39;o-&#39;)
# plt.show()# 方法二&#xff1a;利用轮廓系数法选择k
Scores &#61; [] # 存放轮廓系数
for k in range(7, 12):km &#61; KMeans(n_clusters&#61;k) # 构造聚类器km.fit(tfidf_weight)Scores.append(metrics.silhouette_score(tfidf_weight, km.labels_, metric&#61;&#39;euclidean&#39;))# X &#61; range(17, 20)
# plt.xlabel(&#39;k&#39;)
# plt.ylabel(&#39;轮廓系数&#39;)
# plt.plot(X, Scores, &#39;o-&#39;)
# plt.show()# # 方法三&#xff1a;值越大越好&#xff0c;重点是速度快
# Ss &#61; [] # 存放Ss
# for k in range(12, 30, 2):
# km &#61; KMeans(n_clusters&#61;k) # 构造聚类器
# km.fit(tfidf_weight)
# Ss.append(metrics.calinski_harabaz_score(tfidf_weight, km.labels_))
#
# X &#61; range(2, 5)
# plt.xlabel(&#39;k&#39;)
# plt.ylabel(&#39;Ss&#39;)
# plt.plot(X, Ss, &#39;o-&#39;)
# plt.show()# 求最优k值
print(Scores)
k &#61; 7 &#43; (Scores.index(max(Scores)))

dbscan:
基于密度的聚类&#xff0c;核心点、边界点、离群点。聚类的时候不需要预先指定簇的个数

# DBSCAN参数不好调节
db &#61; DBSCAN(eps&#61;1.25, min_samples&#61;10).fit(tfidf_weight)
print(db.core_sample_indices_)
print(db.labels_)
# 聚类个数为1-n之间会报错
Score &#61; metrics.silhouette_score(tfidf_weight, db.labels_)
print(Score)# 存储每个样本所属的簇
clusterRes &#61; codecs.open(cluster_ResFileName, &#39;w&#39;, encoding&#61;&#39;UTF-8&#39;)
count &#61; 1
while count <&#61; len(db.labels_):clusterRes.write(str(title_list[count - 1]) &#43; &#39;\t&#39; &#43; str(db.labels_[count - 1]))clusterRes.write(&#39;\r\n&#39;)count &#61; count &#43; 1
clusterRes.close()

gsdmm:
一种基于狄利克雷多项式混合模型的收缩型吉布斯采样算法&#xff0c;可以很好的处理稀疏、高纬度的短文本

# GSDMM文本聚类
mgp &#61; MovieGroupProcess(K&#61;35, alpha&#61;0.1, beta&#61;0.1, n_iters&#61;20)
y &#61; mgp.fit(tfidf_matrix, len(tfidf_matrix))
print(y)# 存储每个样本所属的簇
clusterRes &#61; codecs.open(cluster_ResFileName, &#39;w&#39;, encoding&#61;&#39;UTF-8&#39;)
count &#61; 1
while count <&#61; len(y):clusterRes.write(str(title_list[count - 1]) &#43; &#39;\t&#39; &#43; str(y[count - 1]))clusterRes.write(&#39;\r\n&#39;)count &#61; count &#43; 1
clusterRes.close()

模型评估
聚类模型性能评价指标
有监督的分类算法的评价指标通常是accuracy, precision, recall, etc&#xff1b;由于聚类算法是无监督的学习算法&#xff0c;评价指标则没有那么简单了。因为聚类算法得到的类别实际上不能说明任何问题&#xff0c;除非这些类别的分布和样本的真实类别分布相似&#xff0c;或者聚类的结果满足某种假设&#xff0c;即同一类别中样本间的相似性高于不同类别间样本的相似性。聚类模型的评价指标如下&#xff1a;
详细请看http://scikit-learn.org/stable/modules/clustering.html#clustering-performance-evaluation
如果C是真实类别&#xff0c;K是聚类结果&#xff0c;我们定义a和b分别是&#xff1a;
a: 在C和K中都是同一类别的样本对数
b: 在C和K中都是不同类别的样本对数
raw Rand Index 的公式如下:
在这里插入图片描述
C2nsamples 是样本所有的可能组合对.

FMI
在这里插入图片描述

dict_lable &#61; {&#39;eco&#39;: 2, &#39;env&#39;: 0, &#39;sports&#39;: 1, &#39;other&#39;: 3}
data &#61; pd.read_table(r&#39;id2class.txt&#39;, header&#61;None, delim_whitespace&#61;True)
data2 &#61; pd.read_table(r&#39;cluster_dockmResult.txt&#39;, header&#61;None, delim_whitespace&#61;True)
list_true &#61; []
list_pred &#61; []
for i in range(len(data)):data.iloc[i, 1] &#61; dict_lable[data.iloc[i, 1]]list_true.append(data.iloc[i, 1])list_pred.append(data2.iloc[i, 1])# 文档链接 http://scikit-learn.org/stable/modules/clustering.html#clustering-performance-evaluation
# 2.3.10.1 Adjusted Rand index &#xff08;RI&#xff09;
# 2.3.10.2. Mutual Information based scores&#xff08;NMI&#xff09;
# 2.3.10.4. Fowlkes-Mallows scores&#xff08;FMI&#xff09;
# 章节号为文档里面的章节号
print(metrics.adjusted_rand_score(list_true, list_pred)) # RI指数&#xff0c;越接近1越好
print(metrics.adjusted_mutual_info_score(list_true, list_pred)) # NMI指数&#xff0c;越接近1越好
print(metrics.fowlkes_mallows_score(list_true, list_pred)) # FMI指数&#xff0c;越接近1越好

参考数据集&#xff1a;

data_offline:

Total:650(other&#43;3分类)

Idfkm:4 (分类2-4)
在这里插入图片描述

Doc2veckm:3 (分类2-4)较慢

在这里插入图片描述

Idfdb:-1和3

很差&#xff0c;-1为离群点&#xff0c;254个离群点&#xff0c;仅21个为other

Idfdsgmm:9(10)

很慢&#xff0c;只有1类&#xff0c;很差

Ldakm

在这里插入图片描述
测试集中doc2vec&#43;kmeans效果最好&#xff0c;tf-idf&#43;kmeans其次


推荐阅读
author-avatar
天云2_776
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有