Python使用K-means实现文本聚类 python文本聚类例子
csdh11 2024-12-22 14:58 16 浏览
前言
最近遇到了这样一个需求,将N个文本内容聚类成若干个主题词团,减少人工分析文本和分类文本呢的工作量。
实现思路是使用 K-means算法通过高频词对文本内容进行聚类,K-means算法实现原理简单易于理解,缺点是词与词之间的顺序性和相互关系不能在分类中得到体现。实现步骤如下:
- 使用 jieba对文本内容进行分词处理;
- 去掉停用词;
- 使用 TF-IDF算法将上一步过滤后的分词列表转换成矩阵形式;
- 使用 K-means聚类算法对矩阵计算相似性;
- 获取每个聚类的主题词/词团;
准备样本
周杰伦的30首歌曲的歌词金句作为我们聚类样本的内容,保存到 sourceData/周杰伦.txt 文本中。
分词
使用 python的 pip安装结巴分词组件
pip install jieba
定义一个函数方法,读取 周杰伦.txt文件,并对文件内容的每一行文本做分词处理。
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())
# 默认精确模式
seg_list = jieba.cut(line, cut_all=False)
word = "/".join(seg_list)
jiebaword.append(word)
return jiebaword
分词后的文本列表,打印出来如图所示:
停用词
停用词是一些没有具体含义但在文本中经常会出现的词语,例如“的”、“是”、“许多”、“不仅”等。
中文停用词我们可以去网上下载,地址如下:
https://gitcode.com/open-source-toolkit/63e0e/overview?utm_source=highlight_word_gitcode&word=停用词表&isLogin=1
下载后的停用词在一个 hit_stopwords.txt 文件中,如图所示:
停用词不只是只有文字,也包括一些标点符号。
定义一个函数方法读取停用词。
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 文件如图所示。
如果发现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值越高。计算公式:
- IDF 逆文档频率,表示某个词在整个文档集合中的稀有程度。逆文档频率反映了词语在整个文档集合中的普遍性,出现次数越多的词,IDF值越低;反之,则越高。计算公式:
包含词t的文档书 +1 是为了防止除以 0 导致溢出。
总结一下 TF-IDF , TF 表示相同的词在两篇文章中出现的频次越高,两篇文章越相似; IDF 表示某个词在所有文本中出现次数较少,只在某两篇文章中出现几次,则该两篇文章具有较高相似度。
scikit-learn 已经实现了 TF-IDF 算法,我们首先要安装scikit-learn 组件。
pip install scikit-learn
使用python 实现,定义一个函数方法生成 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)
# 转为数组形式
tfidf_arr = tfidf.toarray()
return tfidf_arr
打印输出的矩阵,如下图所示:
这个矩阵的形状是 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 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()
聚类结果保存在 ClusterText.txt 文件中,结果如图所示:
图中有两列数字,第一列数字是从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个文件中。
其中一个cluster文件结果如下:
得到以上分类文档以后,再分别统计各个聚类中频次最高的几个词,定义一个函数方法,代码如下:
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词频统计结果:\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个主题词,效果如图所示:
因为样本做的比较少,所以词频统计的数量不多,所以代表性也不是很强。另一个原因是 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 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__':
# 定义聚类的个数
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)
相关推荐
- OKHttp原理解析(okhttp的作用)
-
Okhttp应该是Android目前非常流行的第三方网络库,尝试讲解他的使用以及原理分析,分成几个部分:...
- 快速教会你优雅的解决TCP客户端端口耗尽的问题
-
Hello,我是Henry,相信各位开发老爷在使用大并发网络连接的时候,可能都遇到过TCP客户端端口耗尽的问题,这是一个常见问题,以下是系统性的解决方案及技术细节:1.理解端口限制的本质...
- 这3个接口基础知识,产品经理需要知道
-
产品经理在工作中,避免不了要阅读接口文档,希望本文能够帮助大家更好的了解接口。接口,即客户端(浏览器)向服务器提交请求,服务器向客户端返回响应。本质就是数据的传输与接收。本文主要介绍接口相关的基础知识...
- Java 11新特性对开发者的影响:让编程更高效、更自由
-
Java11新特性对开发者的影响:让编程更高效、更自由在这个瞬息万变的编程世界里,每一代Java的更新都承载着无数开发者对性能优化、生产力提升以及代码美感追求的期望。作为继Java8之后的首个长期...
- 干货-okHttp的优点-收藏了(okhttp的好处)
-
OkHttp相较于其它的实现有以下的优点.支持SPDY,允许连接同一主机的所有请求分享一个socket。如果SPDY不可用,会使用连接池减少请求延迟。使用GZIP压缩下载内容,且压缩操作对用...
- 如何在 Java 项目中集成 DeepSeek
-
一、使用官方SDK基础集成1.添加依赖(Maven)<dependency><groupId>com.deepseek</groupId>...
- spring cloud gateway 性能优化思路
-
SpringCloudGateway是一个高性能的API网关,但在实际的生产环境中,可能会遇到一些性能瓶颈。以下是一些SpringCloudGateway的性能优化方面:调整线程池...
- 你对Android中的okHttp的使用真的了解吗
-
框架下载地址:https://github.com/square/okhttp今天给大家讲解下网络框架okhttp的使用,这个框架非常强大,很多框架都用它来加载网络资源,目前很多开发者还在用As...
- 京东大佬问我,Nginx并发连接如何设置?详细说明
-
京东大佬问我,Nginx并发连接如何设置?详细说明首先,我需要回忆一下Nginx的并发模型。Nginx是基于事件驱动的异步架构,所以它的并发处理能力和配置参数有很大关系。主要的参数应该包括worker...
- 如何实现一个连接池?一文带你深入浅出,彻底搞懂
-
-前言-【2w1h】是技术领域中一种非常有效的思考和学习方式,即What、Why和How;坚持【2w1h】,可以快速提升我们的深度思考能力。...
- Golang 网络编程(golang 系统编程)
-
TCP网络编程存在的问题:拆包:对发送端来说应用程序写入的数据远大于socket缓冲区大小,不能一次性将这些数据发送到server端就会出现拆包的情况。通过网络传输的数据包最大是1500字节,当TCP...
- Spring6|Spring Boot3有哪些HTTP客户端可以选择
-
个人博客:无奈何杨(wnhyang)个人语雀:wnhyang...
- 10. 常用标准库(标准库有哪些)
-
本章深入解析Go语言核心标准库的关键功能与生产级应用技巧,结合性能优化与安全实践,提供高效开发指南。10.1fmt/io/os10.1.1fmt高级格式化...
- Nginx之连接池(nginx 长连接 连接复用)
-
我们知道Nginx利用连接池来增加它对资源的利用率。下面我们一起来看看Nginx是如何使用连接池的。从上一节模块开始已经慢慢会接触一些Nginx的源码部分来。每个worker进程都有一个独立的ngx...
- 开发者必备的Android开发资源之OkHttp
-
小编在这里给各位Android开发者介绍的资源包括工具、库和网站等。有效地利用它们,将有助于减轻我们的工作量,提高我们的工作效率。为什么需要一个HTTP库Android系统提供了两种HTTP通信类,H...
- 一周热门
- 最近发表
- 标签列表
-
- mydisktest_v298 (34)
- document.appendchild (35)
- 头像打包下载 (61)
- acmecadconverter_8.52绿色版 (39)
- word文档批量处理大师破解版 (36)
- server2016安装密钥 (33)
- mysql 昨天的日期 (37)
- parsevideo (33)
- 个人网站源码 (37)
- centos7.4下载 (33)
- mysql 查询今天的数据 (34)
- intouch2014r2sp1永久授权 (36)
- 先锋影音源资2019 (35)
- jdk1.8.0_191下载 (33)
- axure9注册码 (33)
- pts/1 (33)
- spire.pdf 破解版 (35)
- shiro jwt (35)
- sklearn中文手册pdf (35)
- itextsharp使用手册 (33)
- 凯立德2012夏季版懒人包 (34)
- 冒险岛代码查询器 (34)
- 128*128png图片 (34)
- jdk1.8.0_131下载 (34)
- dos 删除目录下所有子目录及文件 (36)