聚类算法DBSCAN,不用事先指定列别,风控必备

文摘   科技   2024-09-06 11:42   浙江  

聚类分析,是一个无监督学习里面非常重要的课题,无论是在风控还是在其他业务中,通过对大规模的数据分析,找出里面的聚类关系,有助于发现新的问题或者重点问题,我们可以通过对评论文本的分析,我们可以发现消费者关注的产品或服务痛点;通过对来电语音转文本聚类,可以知道公司售后业务的典型问题或者新问题的爆发;通过对昵称聚类,可以发现批量注册用户团伙,通过评论聚类,发现某个商家的核心问题是啥;我们先讲理论,在通过一个文本的案例解释该算法的过程。

风险弹幕
佳喂:sx111505可越et
伽徽:sx111505可聊可约qq
... 

伽韦 sx111505 珂视频箹pz

风险签名

每天 8粒,7天做真男人

每天 6粒,4天做真男人

... 

每天 8粒,3天做真男人

风险评论

好像不卫生吃了拉肚子,口感不好。
... 
别买 不卫生吃了拉肚子

菜品不新鲜,吃了拉肚子

文本聚类方法非常多,我们今天讨论DBSCAN,也是一个非常经典的算法,我们上期讲过的算法,本文本进行简短的回顾,并用一个评价数据的聚类,来进行实战应用,下面就是发现的一个簇的文本。

一、算法概述

DBSCAN是一个出现得比较早(1996年),比较有代表性的基于密度聚类算法,DBSCAN是英文Density-Based Spatial Clustering of Applications with Noise 的缩写,意思为:一种基于密度,同时对于有噪声(即孤立点或异常值)的数据集也有很好的鲁棒的空间聚类算法。DBSCAN将簇定义为密度相连的点的最大集合,能够把具有足够高密度的区域划分为簇,并可在噪声的空间数据库中发现任意形状的聚类。
聚类问题中,如果数据集的各类呈球形分布,可以采用kmeans聚类算法,如果各类数据呈非球形分布(如太极图、笑脸图等),采用kmeans算法效果将大打折扣,这种情况使用DBSCAN聚类算法更为合适,如下图所示,我们的文本聚类,恰好是一些不标准的分布,且事先不确定类别数量,因此用这个算法也是很合适的。

二、 基本概念

DBSCAN的基本概念可以用1个思想,2个参数,3种类别,4种关系来总结。

1、1个核心思想

该算法最核心的思想就是基于密度,直观效果上看,DBSCAN算法可以找到样本点的全部密集区域,并把这些密集区域当做一个一个的聚类簇。
可以简单的理解该算法是基于密度的一种生长,和病毒的传染差不多,只要密度够大,就能传染过去,遇到密度小的,就停止传染,如下图所示。
可视化的网站:https://www.naftaliharris.com/blog/visualizing-dbscan-clustering/

2、2个算法参数,邻域半径R、最少点数目MinPoints

这两个算法参数实际可以刻画什么叫密集:当邻域半径R内的点的个数大于最少点数目R时,就是密集。
这两个参数恰好对应sklearn.cluster.DBSCAN算法中的两个参数为:min_samples eps:eps表示数据点的邻域半径,如果某个数据点的邻域内至少有min_sample个数据点,则将该数据点看作为核心点,如果某个核心点的邻域内有其他核心点,则将它们看作属于同一个簇。如果将eps设置得非常小,则有可能没有点成为核心点,并且可能导致所有点都被标记为噪声。如果将eps设置为非常大,则将导致所有点都被划分到同一个簇。如果min_samples设置地太大,那么意味着更少的点会成为核心点,而更多的点将被标记为噪声。如下所示,指定半径r的点内有满足条件的个点,则可以认为该区域密集

3、3种点的类别,核心点、边界点、噪声点

我们可以简单理解:邻域半径R内样本点的数量大于等于minpoints的点叫做核心点,不属于核心点但在某个核心点的邻域内的点叫做边界点,既不是核心点也不是边界点的是噪声点。
 
我们可以看看,更具体的定义如下:
核心点:对某一数据集D,若样本p的-领域内至少包含MinPts个样本(包括样本p),那么样本p称核心点。
即:
称p为核心点,其中-领域的表达式为:
边界点:对于非核心点的样本b,若b在任意核心点p的-领域内,那么样本b称为边界点。
即:
称b为边界点。
噪声点:对于非核心点的样本n,若n不在任意核心点p的
-领域内,那么样本n称为噪声点。
即:
称n为噪声点。
假设MinPts=4,如下图的核心点、非核心点与噪声的分布:

4、4种点的关系,密度直达、密度可达、密度相连、非密度相连。

密度直达:样本X在核心样本Y的邻域内,则称Y到X是密度直达的,注意这个关系是单向的,反向不一定成立
密度可达:核心样本Y到核心样本P3是密度直达的,核心样本P3到核心样本P2是密度直达的,核心样本P2到样本X是密度直达的,像这种通过P3和P2的中转,在样本Y到样本X建立的关系叫做密度可达。
密度相连:核心样本O到样本Y是密度可达的,同时核心样本O到样本X是密度可达的,这样的关系,我们可以说样本X和样本Y是密度相连的。
对于一系列密度可达的点而言,其邻域范围内的点都是密度相连的,下图所示是一个minPoints为5的领域,红色点为core ponit, 绿色箭头连接起来的则是密度可达的样本集合,在这些样本点的邻域内的点构成了一个密度相连的样本集合,这些样本就属于同一个cluster

三、算法思想

DBSCAN的算法步骤比较简单,主要分成两步。

1、寻找核心点形成临时聚类簇

扫描全部样本点,如果某个样本点R半径范围内点数目>=MinPoints,则将其纳入核心点列表,并将其密度直达的点形成对应的临时聚类簇。

2、合并临时聚类簇得到聚类簇

对于每一个临时聚类簇,检查其中的点是否为核心点,如果是,将该点对应的临时聚类簇和当前临时聚类簇合并,得到新的临时聚类簇。
重复此操作,直到当前临时聚类簇中的每一个点要么不在核心点列表,要么其密度直达的点都已经在该临时聚类簇,该临时聚类簇升级成为聚类簇。
继续对剩余的临时聚类簇进行相同的合并操作,直到全部临时聚类簇被处理。反复寻找这些核心点直接密度可达或密度可达的点,将其加入到相应的类,对于核心点发生密度可达状况的类,给予合并(组建好各个家庭后,如果家庭中长辈之间有亲戚关系,则把家庭合并为一个大家族)

四、sklearn算法介绍

https://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html

1、基本用法

sklearn.cluster.DBSCAN(eps=0.5, *, min_samples=5, metric='euclidean', metric_params=None, algorithm='auto', leaf_size=30, p=None, n_jobs=None )

2、核心参数

  • eps: float,ϵ-邻域的距离阈值
  • min_samples:int,样本点要成为核心对象所需要的 ϵ-邻域的样本数阈值

3、其他参数

  • metric:度量方式,默认为欧式距离,可以使用的距离度量参数有:
    • 欧式距离 “euclidean”
    • 曼哈顿距离 “manhattan”
    • 切比雪夫距离“chebyshev”
    • 闵可夫斯基距离 “minkowski”
    • 带权重闵可夫斯基距离 “wminkowski”
    • 标准化欧式距离 “seuclidean”
    • 马氏距离“mahalanobis”
    • 自己定义距离函数
  • algorithm:近邻算法求解方式,有四种:
    • “brute”蛮力实现
    • “kd_tree” KD树实现
    • “ball_tree”球树实现
    • “auto”上面三种算法中做权衡,选择一个拟合最好的最优算法。
  • leaf_size:使用“ball_tree”或“kd_tree”时,停止建子树的叶子节点数量的阈值
  • p:只用于闵可夫斯基距离和带权重闵可夫斯基距离中p值的选择,p=1为曼哈顿距离, p=2为欧式距离。如果使用默认的欧式距离不需要管这个参数。
  • n_jobs:CPU并行数,若值为 -1,则用所有的CPU进行运算

4、属性

  • core_sample_indices_: 核心点的索引,因为labels_不能区分核心点还是边界点,所以需要用这个索引确定核心点
  • components_:训练样本的核心点
  • labels_:每个点所属集群的标签,也就是聚类的编号,-1代表噪声点

5、算法案例

from sklearn.cluster import DBSCANimport numpy as npX = np.array([[1, 2], [2, 2], [2, 3],              [8, 7], [8, 8], [25, 80]])clustering = DBSCAN(eps=3, min_samples=2).fit(X)
clustering.labels_array([ 0, 0, 0, 1, 1, -1])
0,,0,,0:表示前三个样本被分为了一个群
1,  1:中间两个被分为一个群

-1:最后一个为异常点,不属于任何一个群

五、文本聚类实战

数据简介:O2O商铺食品安全相关评论发现
数据地址:https://tianchi.aliyun.com/dataset/dataDetail?dataId=129832
部分数据内容:

1、基础数据的读取

# 加载所需要的包from sklearn.feature_extraction.text import TfidfVectorizerimport pandas as pdimport os import jieba# 设置工作空间 & 读取数据os.chdir('/Users/wuzhengxiang/Documents/DataSets/评价数据')train = pd.read_csv('train.csv',sep='\t')
# 查看数据大小和形状train.shape(10000, 2)
# 查看下前10条数据train.head(10)Out[2]: label comment0 0 一如既往地好吃,希望可以开到其他城市1 0 味道很不错,分量足,客人很多,满意2 0 下雨天来的,没有想象中那么火爆。环境非常干净,古色古香的,我自己也是个做服务行业的,我都觉得...3 0 真心不好吃 基本上没得好多味道4 0 少送一个牛肉汉堡 而且也不好吃 特别是鸡肉卷 **都不想评论了 谁买谁知道5 0 用美团,图打折。6 0 好难吃水煮鸡杂呀7 0 环境很好,服务很热情,味道非常好,鱼也很新鲜,我和儿子吃的好饱,包子和饺子很好吃哟,8 0 一如既往的好吃,个人更喜欢吃全翅9 0 四个就把我吃饱了……阔以

2、文本向量化

用结巴分词进行分词,并将文本转换成向量,我们这里用的tf-idf 转化,用到了2元的ngram,可以提高文本聚类的稳定性。
#进行分字处理 用结巴分词data = train['comment'].apply(lambda x:' '.join(jieba.lcut(x)) )
# 看看前几条分词的结果for i in data.head(): print(i)一如既往 地 好吃 , 希望 可以 开 到 其他 城市味道 很 不错 , 分量 足 , 客人 很多 , 满意下雨天 来 的 , 没有 想象 中 那么 火爆 。环境 非常 干净 , 古色古香 的 , 我 自己 也 是 个 做 服务行业 的 , 我 都 觉得 他们 的 服务 非常 好 , 场地 脏 了 马上 就 有 阿姨 打扫 。真心 不 好吃 基本上 没 得 好多 味道少送 一个 牛肉 汉堡 而且 也 不 好吃 特别 是 鸡肉 卷 * * 都 不想 评论 了 谁 买 谁 知道

# 进行向量转化vectorizer_word = TfidfVectorizer(max_features=800000, token_pattern=r"(?u)\b\w+\b", min_df = 5, #max_df=0.1, analyzer='word', ngram_range=(1,2) )vectorizer_word = vectorizer_word.fit(data)tfidf_matrix = vectorizer_word.transform(data)

#查看词典的大小len(vectorizer_word.vocabulary_)6968
#查看词典里面的词-部分词语vectorizer_word.vocabulary_
{...'骗人 的': 6878,'的 可能': 4971,'我点 了': 3629,'煮 了': 4706,'了 只有': 886,'一个 人': 92,'人 都': 1078,'不够 吃': 378,'点餐 的': 4648,'的 朋友': 5068,'他们 家': 1134,'蛋炒饭': 5878,'银耳汤': 6677,'好吃 实惠': 2725,'里面 还有': 6645,'还有 免费': 6328,'免费 的': 1371, ...}

3、DBSCAN训练

有了词向量,我们进行聚类模型的训练,DBSCAN主要的两个参数,我们可以进行调整,获取不同的聚类效果。
#  设置下最大可展示的行pd.set_option('display.max_rows', 1000)# 进行模型训练from sklearn.cluster import DBSCANclustering = DBSCAN(eps=0.95, min_samples=5).fit(tfidf_matrix)# 我们看看分了所少个群,每个群的样本数是多少len(pd.Series(clustering.labels_).value_counts())42pd.Series(clustering.labels_).value_counts()-1     90080      6315       288       276       2314      197       16...28      101       1012      103        929       8

4、聚类结果分析

有了分群的结果,我们看看数据准不准,这个群,一看都是吃拉肚子的,我们可以通过这个数据,看看有没有聚集性,如果都是评价的一个商家,那这个商家可能存在严重的食品安全问题,如果是一个消费者或者一群有关系的消费者,那么这个可能是恶意差评,专门靠这一类评价敲诈商家,因此,有了大规模的这种文本挖掘,我们可以发现平台很多隐藏的问题,作为感知或者原因归因,都是非常好的算法。
# 分群标签打进原来的数据train['labels_'] = clustering.labels_
# 抽取编号为5的群看看 可以看到,这个群都是吃拉肚子的反馈,聚类效果还是非常可以的for i in train[train['labels_']==5]['comment']: print(i)吃了拉肚子。一点当地重庆味道都没有吃了拉肚子 弄得不卫生吃了拉肚子 特别不卫生吃了拉肚子,确实卫生不好我吃了拉肚子mmp吃了拉肚子不干净,吃了拉肚子,还发烧了老样子,吃了拉肚子鱼不新鲜,吃了拉肚子……吃了拉肚子,一上午都在医院好像拉肚子了拉肚子太辣,吃了拉肚子吃了拉肚子,现在都十二点多了,还疼的睡不着。我吃了拉肚子……吃了拉肚子。不是正宗湖北油闷味道。。。不新鲜,吃了拉肚子泡椒猪肝吃了拉肚子吃了拉肚子,快要拉死人了。好像不卫生吃了拉肚子,口感不好。味道不行 吃了拉肚子 别买 不卫生吃了拉肚子菜品不新鲜,吃了拉肚子鸭脚变味了,吃了拉肚子吃了拉肚子 有点不新鲜了就是不知道怎么回事我吃了拉肚子吃了拉肚子,味道怪怪的吃了拉肚子!拉肚子!吃了拉肚子,真蛋疼

我们再多抽几个群看看,下面这个是比较好评的
# 抽取编号为5的群看看 可以看到,这个群都是好评的for i in train[train['labels_']==5]['comment']: print(i)上菜快,味道不错环境还不错,上菜速度快,服务态度好环境好,上菜速度快,味道特别好吃,去吃了很多次了菜品很不错,上菜速度快,环境不错便宜,味道好,上菜快,环境好,菜品丰富不错,环境好,上菜速度快。还不错,上菜速度快,口味也合适,可以试一试,经常去味道好 上菜速度快 环境也不错口味不错,上菜速度快,推荐品尝菜品新鲜,味道不错,上菜速度快。经常去,味道不错,上菜速度快。服务很好,上菜速度快。味道不错。环境很好,上菜速度快。下次还来。很好,速度快,环境也不错,,,
我们看看这个14群,里面的描述关键词 肉是臭的,作为一个平台运营者,通过这种评价聚类,就可以找出这种用坏肉的商家,进行一定的处罚,提高消费者体验。
train['labels_'] = clustering.labels_for i in train[train['labels_']==14]['comment']:    print(i)排骨汤都是臭的。难吃,肉是臭的!!!!!!!肉是臭的还卖无语了海南小台农芒  500g 打开一个居然是臭的肉是臭的,吃得一嘴恶心!为什么我总感觉肉是臭的  拿给狗狗吃了 不敢吃难吃,牛肉是臭的nbsp;卤蛋是臭的!!!!肉是臭的,失望透顶今天的肉是臭的,不好吃鱼香肉丝木桶饭#肉是臭的就算了,平菇也是臭的,以后不会再点了肉是臭的 就这样做生意?肉是坏的,不好吃肉是臭的,我吃了一口,全吐了难吃 肉是臭的。鸡肉竟然是臭的!!!!肉是臭的。不好吃。味道还可以!但是!鸡肉居然是臭的!是臭的!猪脚都是臭的。
在找几个看看,有钢丝球系列,也要复购N次的
train['labels_'] = clustering.labels_for i in train[train['labels_']==16]['comment']:    print(i)饭里面居然有钢丝球的钢丝肉里面居然有钢丝球的钢丝……太恶心了要吃死人嘛,都有钢丝球。凉糕里面居然都有钢丝球里面有钢丝球丝丝。#小炒肉#train['labels_'] = clustering.labels_for i in train[train['labels_']==22]['comment']:    print(i)  不错,经常来的,吃了N次了,爽歪歪它家团了N次,味道好,服务态度也好去吃了n次了真心不错,和姐妹聚餐可以去了很多很多次了,一如既往的好,,希望再多一点菜品!!味道好,服务也好,吃了N次了。去了N次了。一如既往的好。加油吃了N次了,一如既往的好吃,辣得过瘾,肉肉好多哟,味道好吃
通过上面的案例,我们可以看到,文本聚类能够将同类问题进行归纳,能够放大隐藏的风险,如果扩大计算规模,我们可以发现更多的问题和风险,加上时间维度,是一个非常高效且有效的隐藏问题挖掘方法。
我们仅仅用了字的相似,并没有用语义相识,我们把文本的向量换成词向量,就可以得到语义相识了,后面有空再写。

···  END  ···

往期精彩:
上市公司地址相似度计算&构建关系图谱
业务实战-如何搭建知识图谱?
策略自动化挖掘、团伙挖掘-课程链接
9大时序异常检测方法汇总
社区发现之标签传播算法(LPA)
情侣、基友、渣男和狗-基于时空关联规则的影子账户挖掘
孤立森林,一个通过XJB乱分进行异常检测的算法
风控策略的自动化生成-利用决策树分分钟生成上千条策略
SynchroTrap-基于松散行为相似度的欺诈账户检测算法
长按关注本号             长按加我好友
      

小伍哥聊风控
风控策略&算法,内容风控、复杂网络挖掘、图神经网络、异常检测、策略自动化、黑产挖掘、反欺诈、反作弊等
 最新文章