sklearn文本聚类分析

面对如今的大数据时代,各种各样的信息令人眼花缭乱,你根本不知道哪些信息是自己所需要的,而一个个看又会浪费很多时间,更不用说对一大堆信息进行分类或总结了。

对于文本信息,我们人是要把内容看完才能知道它意思,然后在此基础上对其进行处理。但对于计算机而言,把内容看完了也不知道意思,因为每个字的意思是人为设定的,计算机并不知道,更何况我们看到的字输入之后在计算机眼里就是一段机器码。

不过不用着急,计算机虽然不知道每个字的意思,但它能清楚地区分每个字的模样,而且记忆力超群,我们人有时候会分不清形近字,但计算机不会。利用这个特性,我们就可以让计算机学会区分文本了,进一步可以让它把意思相近的文章进行分类。

具体步骤就一一看下去吧。

本文用到的数据来自于一个比赛,已在网上公开,为了便于大家直接下载,我把所需要的数据从中提取并放到 GitHub 里了,当然本文的代码也在里面:https://github.com/Stevengz/Text_cluster

需要用到的库:

import pandas as pd
import jieba
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import Birch

数据提取

数据存放在 excel 表中,对于数据处理,我经常使用 Pandas 库,确实比较方便。

表中的文本数据有两列,表达的意思相同,一个是留言主题总结了文本的意思,另一个是留言详情详细叙述了文本:
《sklearn文本聚类分析》
这里选择留言主题,有两个原因,、主题是总结的内容,比较精炼,大部分字都是与想表达的意思相关的,便于提取特征;而详情里面大部分都是描述,字数比较多,一句话里面可能就两三个字是关键,其它不相关的字太多,容易让计算机混淆意思;而且我把两列数据分别进行了训练,确实前者准确率更高。、主题里面字数少,一般就是100个字左右,而详情里面都有好几百个字,选择前者能很大程度上减轻负担。

当然在这里的主要原因是原因一,原因二里面的 “减轻负担” 是附带的福利,不是主要因素,如果两段文本中字数多的那一个有更多比例的关键字,还是推荐选后者。

利用 Pandas 的便捷性:

data = pd.read_excel('文本数据集.xlsx')
x = data.留言主题

这样留言主题那一列的数据就被提取出来了。

文本处理

对于每一段文本,只有一部分词能表达主要意思,很多词并没有明确的意思,只是起到一个起承转合的作用,比如 “是、的…” 这类,而且这些词在文本中会大量重复出现。前面说了计算机不知道每个词的意思,我们主要通过每个词出现的频率等因素来训练它对文本内容进行区分,所以这些经常出现但对文本区分没什么帮助的词需要去除,并将每段文本中进行分词并用空格分隔。

因为是中文文本,所以这里使用 jieba 库,先导入停用词库:

# 停用词
stopwords = []
with open('stopwords.txt', errors='ignore') as sf:
    for line in sf.readlines():
        stopwords.append(line.strip())

这里的停用词库 stopwords.txt 如果你没有,我已将它与文本数据放在一起了,可以自行提取。

分词函数:

# 分词处理
def text_cut(in_text):
    words = jieba.lcut(in_text)
    cut_text = ' '.join([w for w in words if w not in stopwords and len(w) > 1])
    return cut_text
 
x_change = []
for i in x:
    x_change.append(text_cut(i))

这样 x 中的每个文本都被分词并存在新列表中了。

文本中含有英文和数字,但是没有去除,因为两者在数据中代表地区编号,是内容的主体之一。

文本特征提取

向模型输入数据时,不能把文本直接输入进去,需要转换为矩阵的形式。

计算词在向量中的权重可以采用 TF-IDF 算法,比较两个指标:词在当前文本中出现的次数、词在总文本中的次数。前者越高表示越重要,后者越低表示越重要。

解释起来就是,如果一个词在某一文本中出现的次数越多表示它对此文本越重要,但如果这个词在所有文本中出现的次数越多又表示它对此文本越不重要,综合两者才表示一个词对此文本的重要程度。例如一个词只在某个文本中出现多次,但在所有文本中出现的次数很少,那么这个词对于此文本非常重要;若一个词在所有文本中都经常出现,那么这个词对每个文本都不太重要。

sklearn 中有专门的特征提取方法:

# 特征提取
vectorizer = TfidfVectorizer(min_df=2, ngram_range=(1,2), strip_accents='unicode', norm='l2', token_pattern=r"(?u)\b\w+\b")
X = vectorizer.fit_transform(x_change)

这样大写 X 中保存了每个文本的特征向量。

选择模型并训练

对于聚类处理,最常见的肯定是 K-Means 了,这也是我最开始使用的聚类方法,不过在写这篇文章时我又想使用一下别的聚类方法,因为 sklearn 里面包含了很多,功能确实挺强大。当然想使用其它的也可以,毕竟使用流程都是一样的,只是把模型换一下。

这里使用 birch (层级聚类),比较适合于数据量大,类别数K也比较多的情况。birch 算法利用了一个树结构来帮助我们快速的聚类,如果想知道具体原理可以自己去搜,都讲的非常好,这里就不再赘述了。

不过要注意的是,K-Means 必须要指定类别数,而 birch 不需要强制性指定,如果知道类别数最好输入进去,如果不知道,birch 会根据树结构里面的样本情况自己决定类别数:

birch_cluster = Birch(n_clusters=390)
birch_result = birch_cluster.fit_predict(X)

上面 390 是类别的数量,因为所有文本在原始系统分类中最细可分为 390 类左右,我就直接使用最严格的标准来分。当然 Birch 还包含其它参数:threshold —- 分类依据,默认0.5;branching_factor —- 每个类别的最大数量,默认50;compute_labels —- 布尔值,表示是否标示类别输出,默认是True。

birch_result 是生成的所有文本的索引列表,如果 birch_result[0]=30 则表示第 0 个文本被分到第 30 类中去了,所有类别索引为 30 的文本就是一类了。

结果表达

既然我们已经知道了每个文本属于哪一类,就可以直接对它们进行标记。

提取数据时所有内容都放在 data 里面了,我直接在 data 里面新增一列数据,标签就为 “类别编号”,将类别索引保存进去,最后将全部数据保存回源文件,这就将训练结果保存了。

data['类别编号'] = birch_result
pd.DataFrame(data).to_excel('文本数据集.xlsx', sheet_name='Sheet1', index=False, header=True)

看看结果:
《sklearn文本聚类分析》
如果我们想把每类数据提取出来也很简单,随便选择一类提取:

six_data = data[(data.类别编号==6)]

这样 six_data 就是类别编号为 6 的所有数据了,如果还想做其它操作,可以以此为基础,比如提取每类文本的关键字等。

    原文作者:Steven·简谈
    原文地址: https://blog.csdn.net/weixin_44613063/article/details/105971614
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞