自然语言处理中的文本聚类

article/2025/9/12 12:24:46

       声明:代码的运行环境为Python3。Python3与Python2在一些细节上会有所不同,希望广大读者注意。本博客以代码为主,代码中会有详细的注释。相关文章将会发布在我的个人博客专栏《Python自然语言处理》,欢迎大家关注。


       聚类是典型的无监督学习方法,在自然语言处理中,聚类也是至关重要的。

【英文文档的聚类】

'''
英文文档的聚类
'''import numpy as np
import pandas as pd
import nltk
from bs4 import BeautifulSoup
import re
import os
import codecs
from sklearn import feature_extraction
import mpld3# 加载影片数据
titles = open('F:/title_list.txt').read().split('\n')
titles = titles[:100]  # 取前一百个影片名
print(titles[:10])  # 前 10 个片名links = open('F:/link_list_imdb.txt').read().split('\n')
links = links[:100]  # 取前一百个影片介绍synopses_wiki = open('F:/synopses_list_wiki.txt', encoding='utf-8').read().split('\n BREAKS HERE')
synopses_wiki = synopses_wiki[:100]  # 取前一百个来自wiki的简介# 数据清洗,获取html代码中的文本内容
synopses_clean_wiki = []
for text in synopses_wiki:text = BeautifulSoup(text, 'lxml').getText()  # 获取html中的文本信息# strips html formatting and converts to unicodesynopses_clean_wiki.append(text)synopses_wiki = synopses_clean_wikigenres = open('F:/genres_list.txt').read().split('\n')
genres = genres[:100]
# 打印出读进来的相关文本
print(str(len(titles)) + ' titles')
print(str(len(links)) + ' links')
print(str(len(synopses_wiki)) + ' synopses')
print(str(len(genres)) + ' genres')synopses_imdb = open('F:/synopses_list_imdb.txt', encoding='utf-8').read().split('\n BREAKS HERE')
synopses_imdb = synopses_imdb[:100]synopses_clean_imdb = []for text in synopses_imdb:text = BeautifulSoup(text, 'html.parser').getText()# strips html formatting and converts to unicodesynopses_clean_imdb.append(text)synopses_imdb = synopses_clean_imdbsynopses = []for i in range(len(synopses_wiki)):  # 合并wiki和imdb中的内容item = synopses_wiki[i] + synopses_imdb[i]synopses.append(item)# 为每个项目生成索引的全集(在本例中它只是排名),以后我将使用这个得分
ranks = []for i in range(0, len(titles)):ranks.append(i)# 载入 nltk 的英文停用词作为“stopwords”变量
stopwords = nltk.corpus.stopwords.words('english')
print(stopwords[:10])# 载入 nltk 的 SnowballStemmer 作为“stemmer”变量
from nltk.stem.snowball import SnowballStemmer  # 返回词语的原型,去掉ing等stemmer = SnowballStemmer("english")# 这里定义了一个分词器(tokenizer)和词干分析器(stemmer),它们会输出给定文本词干化后的词集合
def tokenize_and_stem(text):  # 词干分析器,返回词语的原型# 首先分句,接着分词,而标点也会作为词例存在tokens = [word for sent in nltk.sent_tokenize(text) for word in nltk.word_tokenize(sent)]filtered_tokens = []# 过滤所有不含字母的词例(例如:数字、纯标点)for token in tokens:if re.search('[a-zA-Z]', token):filtered_tokens.append(token)stems = [stemmer.stem(t) for t in filtered_tokens]return stemsdef tokenize_only(text):  # 分词器,仅分词# 首先分句,接着分词,而标点也会作为词例存在tokens = [word.lower() for sent in nltk.sent_tokenize(text) for word in nltk.word_tokenize(sent)]filtered_tokens = []# 过滤所有不含字母的词例(例如:数字、纯标点)for token in tokens:if re.search('[a-zA-Z]', token):filtered_tokens.append(token)return filtered_tokens# 扩充列表后变成了非常庞大的二维(flat)词汇表
totalvocab_stemmed = []
totalvocab_tokenized = []
for i in synopses:allwords_stemmed = tokenize_and_stem(i)  # 对每个电影的剧情简介进行分词和词干化totalvocab_stemmed.extend(allwords_stemmed)  # 扩充“totalvocab_stemmed”列表allwords_tokenized = tokenize_only(i)totalvocab_tokenized.extend(allwords_tokenized)vocab_frame = pd.DataFrame({'words': totalvocab_tokenized}, index=totalvocab_stemmed)  # 转换为数据框
print('there are ' + str(vocab_frame.shape[0]) + ' items in vocab_frame')print(vocab_frame.head())# 定义向量化参数
from sklearn.feature_extraction.text import TfidfVectorizertfidf_vectorizer = TfidfVectorizer(max_df=0.8, max_features=200000,min_df=0.2, stop_words='english',use_idf=True, tokenizer=tokenize_and_stem, ngram_range=(1,3))  # max_df:用于描述一个词在文档中出现的频率,此处为80%,频率大于这个数,说明该词意义不大;min_df:此处和max_df相对,当一个词出现的频率在二者之间的时候才会被计算tfidf;ngram_range:设置一元模型、二元模型等等
# 在语句前面加:%time 可以在控制台输出运行时间
tfidf_matrix = tfidf_vectorizer.fit_transform(synopses)  # 向量化剧情简介文本
print(tfidf_matrix.shape)
terms = tfidf_vectorizer.get_feature_names()  # 获取特征from sklearn.metrics.pairwise import cosine_similarity  # 计算余弦相似度
dist = 1 - cosine_similarity(tfidf_matrix)  # 计算余弦相似度# k-means聚类
from sklearn.cluster import KMeansnum_clusters = 5
km = KMeans(n_clusters=num_clusters)
km.fit(tfidf_matrix)
clusters = km.labels_.tolist()from sklearn.externals import joblib# 注释语句用来存储你的模型
# 因为我已经从 pickle 载入过模型了
# joblib.dump(km,  'doc_cluster.pkl')
km = joblib.load('doc_cluster.pkl')
clusters = km.labels_.tolist()films = {'title': titles, 'rank': ranks, 'synopsis': synopses, 'cluster': clusters, 'genre': genres}
frame = pd.DataFrame(films, index=[clusters], columns=['rank', 'title', 'cluster', 'genre'])
frame['cluster'].value_counts()grouped = frame['rank'].groupby(frame['cluster'])  # 为了凝聚(aggregation),由聚类分类。
grouped.mean()  # 每个聚类的平均排名(1 到 100)from __future__ import print_function# 按离质心的距离排列聚类中心,由近到远
order_centroids = km.cluster_centers_.argsort()[:, ::-1]for i in range(num_clusters):print("Cluster %d words:" % i, end='')for ind in order_centroids[i, :6]:  # 每个聚类选 6 个词print(' %s' % vocab_frame.ix[terms[ind].split(' ')].values.tolist()[0][0].encode('utf-8', 'ignore'), end=',')print()  # 空行print()  # 空行print("Cluster %d titles:" % i, end='')for title in frame.ix[i]['title'].values.tolist():print(' %s,' % title, end='')print()  # 空行print()  # 空行# 多维尺度分析MDS
import os  # 为了使用 os.path.basename 函数
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn.manifold import MDSMDS()
# 将二维度平面中绘制的点转化成两个元素(components)
# 设置为“precomputed”是因为我们提供的是距离矩阵
# 我们可以将“random_state”具体化来达到重复绘图的目的
mds = MDS(n_components=2, dissimilarity="precomputed", random_state=1)
pos = mds.fit_transform(dist)  # 形如 (n_components, n_samples)
xs, ys = pos[:, 0], pos[:, 1]##可视化聚类
# 用字典设置每个聚类的颜色
cluster_colors = {0: '#1b9e77', 1: '#d95f02', 2: '#7570b3', 3: '#e7298a', 4: '#66a61e'}
# 用字典设置每个聚类名称
cluster_names = {0: 'Family, home, war',1: 'Police, killed, murders',2: 'Father, New York, brothers',3: 'Dance, singing, love',4: 'Killed, soldiers, captain'}# 用 MDS 后的结果加上聚类编号和绘色创建 DataFrame
df = pd.DataFrame(dict(x=xs, y=ys, label=clusters, title=titles))# 聚类归类
groups = df.groupby('label')# 设置绘图
fig, ax = plt.subplots(figsize=(17, 9))  # 设置大小
ax.margins(0.05)  # 可选项,只添加 5% 的填充(padding)来自动缩放(auto scaling)。# 对聚类进行迭代并分布在绘图上
# 我用到了 cluster_name 和 cluster_color 字典的“name”项,这样会返回相应的 color 和 label
for name, group in groups:ax.plot(group.x, group.y, marker='o', linestyle='', ms=12,label=cluster_names[name], color=cluster_colors[name],mec='none')ax.set_aspect('auto')ax.tick_params(axis='x',  # 使用 x 坐标轴which='both',  # 同时使用主刻度标签(major ticks)和次刻度标签(minor ticks)bottom='off',  # 取消底部边缘(bottom edge)标签top='off',  # 取消顶部边缘(top edge)标签labelbottom='off')ax.tick_params(axis='y',  # 使用 y 坐标轴which='both',  # 同时使用主刻度标签(major ticks)和次刻度标签(minor ticks)left='off',  # 取消底部边缘(bottom edge)标签top='off',  # 取消顶部边缘(top edge)标签labelleft='off')ax.legend(numpoints=1)  # 图例(legend)中每项只显示一个点# 在坐标点为 x,y 处添加影片名作为标签(label)
for i in range(len(df)):ax.text(df.ix[i]['x'], df.ix[i]['y'], df.ix[i]['title'], size=8)plt.show()  # 展示绘图# 以下注释语句可以保存需要的绘图
# plt.savefig('clusters_small_noaxes.png', dpi=200)
plt.close()# 层次聚类
from scipy.cluster.hierarchy import ward, dendrogramlinkage_matrix = ward(dist)  # 聚类算法处理之前计算得到的距离,用 linkage_matrix 表示
fig, ax = plt.subplots(figsize=(15, 20))  # 设置大小
ax = dendrogram(linkage_matrix, orientation="right", labels=titles)
plt.tick_params(axis='x',  # 使用 x 坐标轴which='both',  # 同时使用主刻度标签(major ticks)和次刻度标签(minor ticks)bottom='off',  # 取消底部边缘(bottom edge)标签top='off',  # 取消顶部边缘(top edge)标签labelbottom='off')plt.tight_layout()  # 展示紧凑的绘图布局
# 注释语句用来保存图片
plt.savefig('ward_clusters.png', dpi=200)  # 保存图片为 ward_clustersplt.close()

【英文文档聚类结果】

【中文文档聚类】

'''
中文聚类
'''import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import codecs
from scipy import ndimage
from sklearn import manifold, datasets
from sklearn import feature_extraction
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import HashingVectorizer####第一步 计算TFIDF##### 文档预料 空格连接
corpus = []# 读取预料 一行预料为一个文档
for line in open('F:/01_All_BHSpider_Content_Result.txt', 'r', encoding='utf8').readlines():# print linecorpus.append(line.strip())
# print corpus
# 将文本中的词语转换为词频矩阵 矩阵元素a[i][j] 表示j词在i类文本下的词频
vectorizer = CountVectorizer()# 该类会统计每个词语的tf-idf权值
transformer = TfidfTransformer()# 第一个fit_transform是计算tf-idf 第二个fit_transform是将文本转为词频矩阵
tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))# 获取词袋模型中的所有词语
word = vectorizer.get_feature_names()# 将tf-idf矩阵抽取出来,元素w[i][j]表示j词在i类文本中的tf-idf权重
weight = tfidf.toarray()# 打印特征向量文本内容
print('Features length:' + str(len(word)))
resName = "BHTfidf_Result.txt"
result = codecs.open(resName, 'w', 'utf-8')
for j in range(len(word)):result.write(word[j] + ' ')
result.write('\r\n\r\n')# 打印每类文本的tf-idf词语权重,第一个for遍历所有文本,第二个for便利某一类文本下的词语权重
for i in range(len(weight)):# print u"-------这里输出第", i, u"类文本的词语tf-idf权重------"for j in range(len(word)):# print weight[i][j],result.write(str(weight[i][j]) + ' ')result.write('\r\n\r\n')
result.close()####第二步 聚类Kmeans####
print('Start Kmeans:')
from sklearn.cluster import KMeansclf = KMeans(n_clusters=4)  # 景区 动物 人物 国家
s = clf.fit(weight)
print(s)# 中心点
print(clf.cluster_centers_)# 每个样本所属的簇
label = []  # 存储1000个类标 4个类
print(clf.labels_)
i = 1
while i <= len(clf.labels_):print(i, clf.labels_[i - 1])label.append(clf.labels_[i - 1])i = i + 1# 用来评估簇的个数是否合适,距离越小说明簇分的越好,选取临界点的簇个数  958.137281791
print(clf.inertia_)####第三步 图形输出 降维####
from sklearn.decomposition import PCApca = PCA(n_components=2)  # 输出两维
newData = pca.fit_transform(weight)  # 载入N维
print(newData)# 5A景区
x1 = []
y1 = []
i = 0
while i < 400:x1.append(newData[i][0])y1.append(newData[i][1])i += 1# 动物
x2 = []
y2 = []
i = 400
while i < 600:x2.append(newData[i][0])y2.append(newData[i][1])i += 1# 人物
x3 = []
y3 = []
i = 600
while i < 800:x3.append(newData[i][0])y3.append(newData[i][1])i += 1# 国家
x4 = []
y4 = []
i = 800
while i < 1000:x4.append(newData[i][0])y4.append(newData[i][1])i += 1# 四种颜色 红 绿 蓝 黑
plt.plot(x1, y1, 'or')
plt.plot(x2, y2, 'og')
plt.plot(x3, y3, 'ob')
plt.plot(x4, y4, 'ok')
plt.show()

【中文文档聚类结果】

 


http://chatgpt.dhexx.cn/article/eGrK1JH1.shtml

相关文章

什么是嵌入式开发?初学者必看嵌入式学习课程

嵌入式技术是以应用为中心&#xff0c;以计算机技术为基础&#xff0c;并且软硬件可裁剪&#xff0c;适用于应用系统对功能、可靠性、成本、体积、功耗有严格要求的专用计算机系统技术。它最初起源于单片机技术, 是各类数字化的电子、机电产品的核心,主要用于实现对硬件设备的控…

十年经验教你如何学习嵌入式系统

一、如何学习嵌入式系统- - 嵌入式系统的概念 着重理解“嵌入”的概念 &#xff0c;主要从三个方面上来理解。 1、从硬件上&#xff0c;“嵌入”将基于CPU的处围器件&#xff0c;整合到CPU芯片内部&#xff0c;比如早期基于X86体系结构下的计算机&#xff0c;CPU只是有运算器和…

什么是嵌入式?嵌入式开发怎么学

嵌入式开发技术在近几年发展迅速&#xff0c;应用到了我们生活中的各个领域&#xff0c;行业内的人大概对嵌入式开发都有了一定的了解&#xff0c;但是对于刚刚准备入行的小白来说&#xff0c;可能对嵌入式还不是很了解。为了帮助大家更好的学习嵌入式&#xff0c;在这里给大家…

学习嵌入式必读十本书,从C语言到ARM

学习嵌入式必读的十本书籍&#xff0c;按照C语言、数据结构、Linux、C、QT、单片机、ARM的顺序给大家推荐。 01 C语言 凡是计算机、电子、通信、自动化、机械专业的同学&#xff0c;大一的时候必学C语言&#xff0c;而且大部分高校选择的教材都是谭浩强。这本书在网上的评价褒…

如何学习嵌入式Linux_韦东山

在线课堂&#xff1a;https://www.100ask.net/index&#xff08;课程观看&#xff09; 论  坛&#xff1a;http://bbs.100ask.net/&#xff08;学术答疑&#xff09; 开 发 板&#xff1a;https://100ask.taobao.com/ &#xff08;淘宝&#xff09;      https://weid…

新手如何学习学嵌入式开发?

新手如何学习嵌入式开发&#xff1f; 这个问题相信是困扰所有嵌入式初学者的难题&#xff0c;下面的内容是嵌入式学习必学的&#xff1a; C语言; C;操作系统;计算机组成原理; linux编程; 51单片机; arm;硬件编程语言(FPGA);模拟电路&数字电路。 1、cc语言&#xff0c;这是…

嵌入式如何学习

嵌入式的学习步骤如何&#xff0c;嵌入式涵盖哪些方面。 相信下面两位的回答&#xff0c;会让大家有一个基本的脉络。 著作权归作者所有。 商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 第一位&#xff1a; 作者&#xff1a;李brooks 链接&#xff1a;htt…

嵌入式到底该怎么学

想学习单片机的同学可以关注、私信我或者在评论区回复我要入门。很多人都不知道嵌入式怎么学&#xff0c;这一期我就简单说一下我的理解。嵌入式这个概念太广了&#xff0c;可能很多人认为嵌入式就是嵌入式Linux。但是其实并不仅仅只有Linux&#xff0c;像STM32&#xff0c;51单…

如何高效学习嵌入式?

近几年来&#xff0c;随着移动互联网、物联网的迅猛发展&#xff0c;嵌入式技术日渐普及&#xff0c;在通讯、网络、工控、医疗、电子等领域发挥着越来越重要的作用;随着嵌入式技术及相关产品不断渗透到人们日常生活&#xff0c;大大小小公司对于嵌入式开发人才招聘需求猛增。但…

嵌入式学习的正确方法

嵌入式专业是一门实践性非常强的学科&#xff0c;只有多动手&#xff0c;多实践&#xff0c;多编程&#xff0c;多调试&#xff0c;多看书&#xff0c;多思考才能真正掌握好嵌入式开发技术。那么&#xff0c;如何从零开始学习嵌入式开发技术&#xff0c; 进入嵌入式开发大门呢&…

使用LoadRunner-运行负载测试

1.运行负载测试 • 录制好脚本之后&#xff0c;返回首页&#xff0c;点击“Run Load Tests”&#xff1b; • 如果遇到以下问题&#xff0c;点击“Close”&#xff0c;右击桌面LoadRunner选择“以管理员身份运行”&#xff0c;如图&#xff1a; 2.运行脚本 • 点击Run Load Tes…

Ubuntu 下 CPU 负载测试

在嵌入式系统开发的时候&#xff0c;我们要评估系统散热情况需要满载测试或者测试系统调度情况需要让 cpu 满载运行的软件&#xff1a;stress 堪称利器 这个不算原创&#xff0c;只是自己偶尔用&#xff0c;经常忘记命令&#xff0c;所以记录一下&#xff0c;以后好找 stress 安…

负载测试压力测试强度测试稳定性测试

你看&#xff0c;如标题所示&#xff0c;测试可以分为这么多种。实际上&#xff0c;这只是一种性能测试的分类。按照不同的标准&#xff0c;还可以有别的划分。 1、按开发阶段&#xff1a;单元测试、集成测试、系统测试、验收测试 2、按测试实施组织&#xff1a;α测试&#x…

软件性能测试——负载测试的最佳实践

性能测试中最容易被误解的部分之一就是负载测试。大多数人认为所有性能测试就是负载测试&#xff0c;但这是不准确的。有许多类型的测试组成性能测试。在进行负载测试之前要考虑的问题之前&#xff0c;让我们仔细研究一下负载测试的基本信息。 负载测试是性能测试的子集。比如…

jmeter的负载测试

1.先在测试计划创建线程组和录制Case 1 1.1 选择测试计划 2 1.2创建线程组 3 1.3创建录制控制器 4 1.4结果如下&#xff1a; END 2.先在jmeter设置代理服务器 2.1 在工作台建立代理服务器 2.2结果如下&#xff1a; 3 &#xff08;注意默认端口是8080,当然可以改) 4 目…

Loadrunner之使用Controller负载测试

进入controller中&#xff0c;导入做好的脚本&#xff0c;开始设置场景&#xff08;条件&#xff09;。 添加虚拟用户数量&#xff1a;如设置50个VUser&#xff08;50个虚拟用户&#xff09;&#xff0c;每隔几秒增加几个虚拟用户。设置退出条件&#xff1a;完成一个退出一个&…

loadRunner之负载测试

一、loadrunner负载测试监控 在应用程序中生成负载时&#xff0c;我们希望实时了解应用程序的性能以及潜在的瓶颈。使用 LoadRunner 的一套集成监控器可以评测负载测试期间系统每一层的性能以及服务器和组件的性能。 LoadRunner 包含多种后端系统主要组件 &#xff08;如 Web、…

2.负载测试

负载测试 负载测试主要关注在并发用户数或每秒请求数方面评估系统的当前性能。 什么是负载测试 负载测试是一种性能测试&#xff0c;用于确定系统在正常和峰值条件下的行为。 负载测试用于确保当许多用户同时访问应用程序时&#xff0c;应用程序的性能令人满意。 您应该运行负…

负载测试的最佳实践

当任何软件开发项目接近完成时&#xff0c;它可能已经通过了大量的测试&#xff0c;特别是在测试和开发同时进行的敏捷测试环境中。但是无论您运行了多少测试&#xff0c;一旦您的应用程序接近完成&#xff0c;实际上只有一种方法可以知道您的软件是否能够处理大量最终用户的实…

Split Pairs

问题描述&#xff1a; Split the string into pairs of two characters. If the string contains an odd number of characters, then the missing second character of the final pair should be replaced with an underscore (_). &#xff08;将一个字符串两两分开&#x…