相似文本聚类与调参

相似文本聚类与调参将相似的文本聚合到一起

?作者: 小小明-代码实体

?博客主页:https://blog.csdn.net/as

?欢迎点赞 ? 收藏 ⭐留言 ? 欢迎讨论!

在这里插入图片描述

之前我在《批量模糊匹配的三种方法》一文中讲述了如何匹配最相似文本的方法,其中使用Gensim进行批量模糊匹配,是使用了稀疏的词向量计算相似度,速度相对前面的方法极快。

去年我有使用sklearn做过文本聚类,今天我就给大家演示一下如何在一大堆文本中自动寻找出相似的文本进行聚类,主要思路有:

  1. 将每个文本进行分词
  2. 根据词频或TF-IDF生成词向量
  3. 使用DBSCAN聚类算法对词向量矩阵计算余弦相似度并连接聚类

之前使用Gensim计算出的词频向量无法直接作为sklearn库的输入,需要进行如下转换为专门的稀疏矩阵对象:

from scipy import sparse data, rows, cols = [], [], [] for i, row in enumerate(data_corpus): for e, c in row: rows.append(i) cols.append(e) data.append(c) data = sc.csr_matrix((data, (rows, cols))) 

为了方便,今天词向量和聚类算法都使用sklearn库,不再使用Gensim库。

首先我们读取测试数据:

import pandas as pd import numpy as np import jieba df = pd.read_csv("所有客户.csv", encoding="gbk") 

中文分词

分词的好坏会直接影响后续词向量的表现,我们可以根据数据集的情况自定义词汇,例如我根据前20条数据的情况增加相应的药店品牌:

words = ["元岗", "铭心堂", "金健民", "祺和", "钜富", "杏园春", "天平民康"] for word in words: jieba.add_word(word) 

如果我们需要分词的数据集存在停用词,可以使用如下代码将所有非中文字符(不含几个生僻字)删除:

df.user = df.user.str.replace("[^一-龟]+", "", regex=True) 

然后执行分词并查看结果:

data_split_word = df.user.apply(jieba.lcut).apply(" ".join) data_split_word.head(20) 
0 [珠海, 广药, 康鸣, 医药, 有限公司] 1 [深圳市, 宝安区, 中心医院] 2 [中山, 火炬, 开发区, 伴康, 药店] 3 [中山市, 同方, 医药, 有限公司] 4 [广州市, 天河区, 元岗, 金健民, 医药, 店] 5 [广州市, 天河区, 元岗, 居健堂, 药房] 6 [广州市, 天河区, 元岗, 润佰, 药店] 7 [广州市, 天河区, 元岗, 协心, 药房] 8 [广州市, 天河区, 元岗, 心怡, 药店] 9 [广州市, 天河区, 元岗, 永亨堂, 药店] 10 [广州市, 天河区, 员村, 德晖, 中, 西药店] 11 [广州市, 天河区, 员村, 东兴, 堂昌, 乐园, 药店] 12 [广州市, 天河区, 员村, 合家欢, 大, 药房] 13 [广州市, 天河区, 员村, 慷乐, 医药, 商店] 14 [广州市, 天河区, 员村, 为民, 永康, 药店] 15 [广州市, 天河区, 珠江, 新城, 钜富, 药店] 16 [广州市, 天河区, 珠江, 新城, 祺和, 药店] 17 [广州市, 天河区, 珠江, 新城, 杏园春, 药店] 18 [广州市, 天河, 沙河, 云芝, 中药店] 19 [广州市, 天河, 天平民康, 药店] Name: user, dtype: object 

当前前20条数据勉强算是分词达标。

当然明显药房和药店这些词的含义相同,如果我需要进一步减少影响,完全可以批量将其替换为一致的词汇。

创建词频向量

然后我们需要使用sklearn建立词频向量:

from sklearn.feature_extraction.text import CountVectorizer count = CountVectorizer() title_vec = count.fit_transform(data_split_word) 

注意:如果我们需要使用TF-IDF模型当某个词在多个文本中出现时降低其权重,直接将CountVectorizer修改为TfidfVectorizer即可。

title_vec是个稀疏矩阵:<43487x24882 sparse matrix of type '
' with stored elements in Compressed Sparse Row format>

可以看看稀疏矩阵的结果:

print(title_vec[:2]) 
 (0, 17283) 1 (0, 10626) 1 (0, 11177) 1 (0, 5944) 1 (0, 13505) 1 (1, 16416) 1 (1, 9475) 1 (1, 2833) 1 

SciPy 稀疏矩阵:https://www.runoob.com/scipy/scipy-sparse-matrix.html

DBSCAN原理简介

img

DBSCAN的核心参数是eps和min_samples,eps表示上图圆的半径,如果两个词向量的距离小于eps就会被连接在一起,而一个点能否成为中心点取决于圆内的点是否超过min_samples。

如何计算两个词向量之间的距离呢?sklearn内置了各种公式。

各类距离公式可查阅:https://xiao-xiaoming.github.io/DataMiningGuide/#/chapter-2

下面编写一个方法用于测试各种公式计算距离:

from sklearn.metrics import pairwise_distances def calc_distance(i, j, metric="l1"): x, y = title_vec[i].toarray(), title_vec[j].toarray() print(i, j, data_split_word[i], "|", data_split_word[j], pairwise_distances(x, y, metric=metric)[0][0]) 

先测试曼哈顿距离:

for i, j in combinations(range(3, 11), 2): calc_distance(i, j) 
3 4 中山市 同方 医药 有限公司 | 广州市 天河区 元岗 金健民 医药 店 7.0 3 5 中山市 同方 医药 有限公司 | 广州市 天河区 元岗 居健堂 药房 9.0 3 6 中山市 同方 医药 有限公司 | 广州市 天河区 元岗 润佰 药店 9.0 3 7 中山市 同方 医药 有限公司 | 广州市 天河区 元岗 协心 药房 9.0 3 8 中山市 同方 医药 有限公司 | 广州市 天河区 元岗 心怡 药店 9.0 3 9 中山市 同方 医药 有限公司 | 广州市 天河区 元岗 永亨堂 药店 9.0 3 10 中山市 同方 医药 有限公司 | 广州市 天河区 员村 德晖 中 西药店 9.0 4 5 广州市 天河区 元岗 金健民 医药 店 | 广州市 天河区 元岗 居健堂 药房 4.0 4 6 广州市 天河区 元岗 金健民 医药 店 | 广州市 天河区 元岗 润佰 药店 4.0 4 7 广州市 天河区 元岗 金健民 医药 店 | 广州市 天河区 元岗 协心 药房 4.0 4 8 广州市 天河区 元岗 金健民 医药 店 | 广州市 天河区 元岗 心怡 药店 4.0 4 9 广州市 天河区 元岗 金健民 医药 店 | 广州市 天河区 元岗 永亨堂 药店 4.0 4 10 广州市 天河区 元岗 金健民 医药 店 | 广州市 天河区 员村 德晖 中 西药店 6.0 5 6 广州市 天河区 元岗 居健堂 药房 | 广州市 天河区 元岗 润佰 药店 4.0 5 7 广州市 天河区 元岗 居健堂 药房 | 广州市 天河区 元岗 协心 药房 2.0 5 8 广州市 天河区 元岗 居健堂 药房 | 广州市 天河区 元岗 心怡 药店 4.0 5 9 广州市 天河区 元岗 居健堂 药房 | 广州市 天河区 元岗 永亨堂 药店 4.0 5 10 广州市 天河区 元岗 居健堂 药房 | 广州市 天河区 员村 德晖 中 西药店 6.0 6 7 广州市 天河区 元岗 润佰 药店 | 广州市 天河区 元岗 协心 药房 4.0 6 8 广州市 天河区 元岗 润佰 药店 | 广州市 天河区 元岗 心怡 药店 2.0 6 9 广州市 天河区 元岗 润佰 药店 | 广州市 天河区 元岗 永亨堂 药店 2.0 6 10 广州市 天河区 元岗 润佰 药店 | 广州市 天河区 员村 德晖 中 西药店 6.0 7 8 广州市 天河区 元岗 协心 药房 | 广州市 天河区 元岗 心怡 药店 4.0 7 9 广州市 天河区 元岗 协心 药房 | 广州市 天河区 元岗 永亨堂 药店 4.0 7 10 广州市 天河区 元岗 协心 药房 | 广州市 天河区 员村 德晖 中 西药店 6.0 8 9 广州市 天河区 元岗 心怡 药店 | 广州市 天河区 元岗 永亨堂 药店 2.0 8 10 广州市 天河区 元岗 心怡 药店 | 广州市 天河区 员村 德晖 中 西药店 6.0 9 10 广州市 天河区 元岗 永亨堂 药店 | 广州市 天河区 员村 德晖 中 西药店 6.0 

image-20220803224943924

从目前的数据来看,可以认为曼哈顿距离在4以内的认为相似。

for i, j in combinations(range(3, 11), 2): calc_distance(i, j, "l2") 

而欧几里得距离下,可以认为距离在2以内的相似:

image-20220803225527716

而余弦相似度距离下或许应该设置距离0.4以内认为相似:

image-20220803225751804

DBSCAN聚类

今天我们就使用余弦相似度进行聚类:

from sklearn.cluster import DBSCAN model = DBSCAN(eps=0.4, min_samples=5, metric="cosine") model.fit(title_vec) df['label'] = model.labels_ 

结果中标签-1未找到相似文本的节点,标签0往往表示大量的数据都被聚类到了这里面:

print("未被聚类:", df.query("label==-1").shape[0]) print("都被聚在一起:", df.query("label==0").shape[0]) print("正常的聚类:", df.query("label not in (-1,0)").shape[0]) print("产生类别数:", df.label.nunique()-2) 
未被聚类: 5727 都被聚在一起: 35840 正常的聚类: 1920 产生类别数: 203 

我们可以不断调整eps和metric得到更准确的结果。下面我们预览一下成功聚类的部分的聚类结果:

for label, df_split in df.query("label not in (-1,0)").groupby("label"): print(label, df_split.user.to_list()) if label > 50: break 

image-20220803231959828

个人觉得结果还算达标~

当然,这种文本聚类问题不可能100%结果完全准确,这需要大家根据数据集的情况,细化到每个步骤去调整,最好能够自定义距离计算公式(metric参数支持传入自动化函数)~

相关参考:

使用sklearn处理经纬度的三种距离计算与地图可视化

https://xxmdmst.blog.csdn.net/article/details/

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/206459.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午3:39
下一篇 2026年3月19日 下午3:39


相关推荐

  • 计算机程序的构造和解释——笔记(一)

    计算机程序的构造和解释——笔记(一)

    2021年7月9日
    70
  • matlab中wavedec2,[ZZ] matlab中小波变换函数dwt2和wavedec2 系数提取函数appcoef2和detcoef2…

    matlab中wavedec2,[ZZ] matlab中小波变换函数dwt2和wavedec2 系数提取函数appcoef2和detcoef2…https://zhidao.baidu.com/question/88038464.htmlDWT2是二维单尺度小波变换,其可以通过指定小波或者分解滤波器进行二维单尺度小波分解。而WAVEDEC2是二维多尺度小波分解。DWT2的一种语法格式是[cA,cH,cV,cD]=dwt2(X,‘wname‘);而对应的WAVEDEC2的语法格式是[C,S]=wavedec2(X,N,‘wname‘),其中…

    2022年7月23日
    11
  • Seedance 2.0正式接入豆包

    Seedance 2.0正式接入豆包

    2026年3月13日
    2
  • Android studio断点调试

    Android studio断点调试有人说Android的调试是最坑的,那我只能说是你不会用而已,我可以说AndroidStudio的调试是我见过最棒的。下面会将debug模式和Attach模式的断点调试好了开始写一个简单的调试程序,我们先来一个for循环设置断点(点击红点位置添加或取消断点)点击debug模式运行查看调试面板一、简单调试1.stepover:…

    2022年5月21日
    223
  • 没错,列式存储非常牛。但是,Ta还可以更高效

    没错,列式存储非常牛。但是,Ta还可以更高效采用列存可以只读取需要的列 在总列数较多 计算涉及的列较少时 能减少硬盘访问量 提高性能 但仅此还不够 列存数据仓库还要在数据压缩 多线程并行和查找计算等方面做优化以将列存的效果做到最佳

    2026年3月20日
    3
  • SATA硬盘的数据和电源接口定义

    SATA硬盘的数据和电源接口定义现在 nbsp SATA 设备越来越普及 包括 STAT 硬盘和光驱基本都已经是 nbsp SATA 接口的了 以前的老式电源输出接口一般都是 20 针供主板加上 4 针的电源供硬盘也就是说以前的电脑电源给硬盘供电没有设计 15 针 nbsp SATA 接口的供电 现在的 nbsp SATA 电源是 15 针的 那么我们有没有办法用以前的老式电源带动现在的新设备呢 答案是肯定的 有转接线可以把 4pin 转换为硬盘接口这就是转接线 黑的就是硬盘接口

    2026年3月19日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号