当前位置: 首页 > news >正文

Python使用K-means实现文本聚类

Python使用K-means实现文本聚类

https://files.mdnice.com/user/70526/524f1c9e-1d39-4d51-a238-f8572cd0e7df.png

前言

最近遇到了这样一个需求,将N个文本内容聚类成若干个主题词团,减少人工分析文本和分类文本的工作量。

实现思路是使用 K-means算法通过高频词对文本内容进行聚类,K-means算法实现原理简单易于理解,缺点是词与词之间的顺序性和相互关系不能在分类中得到体现。实现步骤如下:

  • 使用 jieba对文本内容进行分词处理;
  • 去掉停用词;
  • 使用 TF-IDF算法将上一步过滤后的分词列表转换成矩阵形式;
  • 使用 K-means聚类算法对矩阵计算相似性;
  • 获取每个聚类的主题词/词团;

准备样本

周杰伦的30首歌曲的歌词金句作为我们聚类样本的内容,保存到 sourceData/周杰伦.txt 文本中。

https://files.mdnice.com/user/70526/524f1c9e-1d39-4d51-a238-f8572cd0e7df.png

分词

使用 pythonpip安装结巴分词组件

pip install jieba

定义一个函数方法,读取 周杰伦.txt文件,并对文件内容的每一行文本做分词处理。

import jiebadef 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())# 默认精确模式seg_list = jieba.cut(line, cut_all=False)word = "/".join(seg_list)jiebaword.append(word)return jiebaword

分词后的文本列表,打印出来如图所示:

https://files.mdnice.com/user/70526/524f1c9e-1d39-4d51-a238-f8572cd0e7df.png

停用词

停用词是一些没有具体含义但在文本中经常会出现的词语,例如“的”、“是”、“许多”、“不仅”等。

中文停用词我们可以去网上下载,地址如下:

https://gitcode.com/open-source-toolkit/63e0e/overview?utm_source=highlight_word_gitcode&word=停用词表&isLogin=1

下载后的停用词在一个 hit_stopwords.txt 文件中,如图所示:

https://files.mdnice.com/user/70526/524f1c9e-1d39-4d51-a238-f8572cd0e7df.png

停用词不只是只有文字,也包括一些标点符号。

定义一个函数方法读取停用词。

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

定义一个函数方法从样本分词列表中过滤掉停用词,过滤后的结果保存到 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 文件如图所示。

https://files.mdnice.com/user/70526/524f1c9e-1d39-4d51-a238-f8572cd0e7df.png

如果发现CleanWords.txt 文件中还有一些词语会影响聚类的效果,可以使用如下语句添加停用词。


for i in range(30):stopword.append(str(i+1))stopword.append('一路')
stopword.append('向北')

TF-IDF算法

为了让计算机能够理解词语的相似度,我们可以将文本格式的数据转换成矩阵类型的数据, TF-IDF矩阵在这方面是应用最为广泛的。

TF-IDF(Term Frequency-Inverse Document Frequency,词频-逆文档频率)是一种在信息检索和文本挖掘领域广泛使用的统计方法,用于评估一个词在文档或语料库中的重要程度。

  • TF 词频,表示某个词在文档中出现的频率。词频反映了词语在文档中的重要性,出现次数越多,TF值越高。计算公式:

https://files.mdnice.com/user/70526/524f1c9e-1d39-4d51-a238-f8572cd0e7df.png

  • IDF 逆文档频率,表示某个词在整个文档集合中的稀有程度。逆文档频率反映了词语在整个文档集合中的普遍性,出现次数越多的词,IDF值越低;反之,则越高。计算公式:

https://files.mdnice.com/user/70526/524f1c9e-1d39-4d51-a238-f8572cd0e7df.png

包含词t的文档书 +1 是为了防止除以 0 导致溢出。

总结一下 TF-IDFTF 表示相同的词在两篇文章中出现的频次越高,两篇文章越相似; IDF 表示某个词在所有文本中出现次数较少,只在某两篇文章中出现几次,则该两篇文章具有较高相似度。

scikit-learn 已经实现了 TF-IDF 算法,我们首先要安装scikit-learn 组件。

pip install scikit-learn

使用python 实现,定义一个函数方法生成 TF-IDF 矩阵。

from sklearn.feature_extraction.text import TfidfVectorizerdef 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)# 转为数组形式tfidf_arr = tfidf.toarray()return tfidf_arr

打印输出的矩阵,如下图所示:

https://files.mdnice.com/user/70526/524f1c9e-1d39-4d51-a238-f8572cd0e7df.png

这个矩阵的形状是 30 * 217 ,它表示 217 个分词在 30 个文本中的 TF-IDF 值,值为0表示在此文章中没有出现过。由于打印的不是完整的矩阵,所以上图中的矩阵没有将非0的值显示出来。

K-means聚类

K-Means 聚类是一种常用的无监督学习算法,用于将数据集分成K个簇(cluster),使得簇内的数据点彼此之间尽可能相似,而簇间的数据点尽可能不同。 K-Means 算法的目标是最小化簇内数据点到簇中心的距离之和。

我们需要使用 nltk 组件调用 K-Means 算法。

pip install nltk

定义一个函数方法,获取K-Means 聚类。

from nltk.cluster import KMeansClusterer, cosine_distance
import pandas as pddef 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()

聚类结果保存在 ClusterText.txt 文件中,结果如图所示:

https://files.mdnice.com/user/70526/524f1c9e-1d39-4d51-a238-f8572cd0e7df.png

图中有两列数字,第一列数字是从0到29按顺序排列的数字,表示30个文本的序号。第二列数字表示5个聚类的序号 0~4

获取主题词

前面几步已经得到了对周杰伦歌词的聚类索引,但是我们并不清楚这些聚类索引代表什么含义,所以我们可以将这5个聚类里词频最高的几个词给提取出来。

定义一个函数方法,获取分类文档。

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个歌词文本的聚类结果分别放入5个文件中。

https://files.mdnice.com/user/70526/524f1c9e-1d39-4d51-a238-f8572cd0e7df.png

其中一个cluster文件结果如下:

https://files.mdnice.com/user/70526/524f1c9e-1d39-4d51-a238-f8572cd0e7df.png

得到以上分类文档以后,再分别统计各个聚类中频次最高的几个词,定义一个函数方法,代码如下:

from collections import Counterdef 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] += 1print('主题' + str(i) + '----------------------------------------------------\n词频统计结果:\n')fw.write('主题' + str(i) + '----------------------------------------------------\n词频统计结果:\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()

执行结果保存在 title.txt 文件中,我这里参数 top_n 是传的3,表示获取3个主题词,效果如图所示:

https://files.mdnice.com/user/70526/524f1c9e-1d39-4d51-a238-f8572cd0e7df.png

因为样本做的比较少,所以词频统计的数量不多,所以代表性也不是很强。另一个原因是 K-means 算法是一种无监督算法,一开始要定义好聚类的数量,算法根据聚类的数量随机选取聚类中心点,中心点选的不准会极大影响聚类结果的准确度。所以可以定义不同的聚类数量多计算几次,直到满意为止。

主流程方法

主流程 main 方法基本是调用上文中列表的所有函数方法,按步骤开始执行。

此外,还定义了一个 delete_files_in_directory 函数用来在生成聚类结果之前先删除上一次生成的结果,否则生成的结果txt文件会叠加上一次的结果。

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 osdef 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__':# 定义聚类的个数cluster = 5# 定义主题词个数top_n = 3# 删除上一次的结果数据delete_files_in_directory('resultData/周杰伦')# 结巴分词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)# 统计出主题词get_title(cluster, top_n)


http://www.mrgr.cn/news/64312.html

相关文章:

  • XtraBackup开源热备工具
  • CPU用户时间百分比
  • LeetCode100之找到字符串中所有字母异位词(438)--Java
  • 100M宽带测速只有20M
  • 代码优雅的规范
  • Linux常见命令合集
  • Respiratory Physiology Neurobiology
  • TCP编程-socket(套接字)编程实战1
  • RK3568平台开发系列讲解(中断篇)延迟工作实验
  • vscode makfile编译
  • 电阻基础知识(六)-电阻的失效模式和失效机理
  • 【MacOS实操】如何基于SSH连接远程linux服务器
  • redis详细教程(7.哨兵)
  • 《GBDT 算法的原理推导》 11-13初始化模型 公式解析
  • LangChain学习之路
  • 【Comsol教程】计算流道中的流量
  • 一般无人机和FPV无人机的区别
  • WorkFlow Communicator之TCPServer(上)
  • QT打包Macosx应用发布App Store简易流程
  • 关于函数指针的一些例子说明
  • 探讨 Vue2 和 Vue3 中双向绑定机制的优化与差异
  • MybatisPlus - 核心功能
  • B3628 机器猫斗恶龙
  • C++队列
  • Linux系列-进程的概念
  • 02LangChain 实战课——安装入门