数据挖掘——DBSCAN聚类学习及使用


  在现实生活中收集到的好多数据是没有标签的,要在上面做一些数据挖掘和分析的工作,首先能用到的就是通过聚类的方式来得到数据的类别。然后再去发现一些相关的知识。因此,近期准备将各种聚类算法进行学习。

  k-means算法大家都已经很熟悉了,它是基于距离计算的聚类方法,而且它旨在发现球状簇。若数据的分别刚好呈现的是其他的形状(如下图1),那么我们就要用到了基于密度的聚类方法,也就是今天我们学习的DBSCAN(Density-Based Spatial Clustering of Applications with Noise,具有噪声的基于密度的聚类方法)算法。该算法可以发现任意形状的簇。

在这里插入图片描述

一、基本思想

  根据下面的图形象来说,我们可以认为这是系统在众多样本点中随机选中一个,围绕这个被选中的样本点画一个圆,规定这个圆的半径以及圆内最少包含的样本点,如果在指定半径内有足够多的样本点在内,那么这个圆圈的圆心就转移到这个内部样本点,继续去圈附近其它的样本点,类似传销一样,继续去发展下线。等到这个滚来滚去的圈发现所圈住的样本点数量少于预先指定的值,就停止了。那么我们称最开始那个点为核心点,如A,停下来的那个点为边界点,如B、C,没得滚的那个点为离群点,如N
在这里插入图片描述

1、原理

DBSCAN算法将数据点分为三类:

  • 核心点:在半径Eps内含有超过MinPts数目的点
  • 边界点:在半径Eps内点的数量小于MinPts,但是落在核心点的邻域内
  • 噪音点:既不是核心点也不是边界点的点
2、参数选择

所以,首先我们需要指定半径EpsMinPts的值。

  • 半径:半径是最难指定的 ,大了,圈住的就多了,簇的个数就少了;反之,簇的个数就多了,这对我们最后的结果是有影响的。我们这个时候K距离可以帮助我们来设定半径r,也就是要找到突变点,比如:

在这里插入图片描述
  以上虽然是一个可取的方式,但是有时候比较麻烦 ,大部分还是都试一试进行观察,用k距离需要做大量实验来观察,很难一次性把这些值都选准。

  • MinPts:这个参数就是圈住的点的个数,也相当于是一个密度,一般这个值都是偏小一些,然后进行多次尝试
3、算法的伪代码

在这里插入图片描述

4、python代码实现
import numpy as np
import random
import matplotlib.pyplot as plt
import time

def findNeighbor(j,X,eps):
"查找点j的邻域"
    N=[]
    for p in range(X.shape[0]):   #找到所有领域内对象
        temp=np.sqrt(np.sum(np.square(X[j]-X[p])))   #欧氏距离
        if(temp<=eps):
            N.append(p)
    return N


def dbscan(X,eps,min_Pts):
    k=-1
    NeighborPts=[]      #array,某点领域内的对象
    Ner_NeighborPts=[]
    fil=[]                                      #初始时已访问对象列表为空
    gama=[x for x in range(len(X))]            #初始时将所有点标记为未访问
    cluster=[-1 for y in range(len(X))]
    while len(gama)>0:
        j=random.choice(gama)  #随机选择一个点
        gama.remove(j)  #未访问列表中移除
        fil.append(j)   #添加入访问列表
        NeighborPts=findNeighbor(j,X,eps)
        if len(NeighborPts) < min_Pts:
            cluster[j]=-1   #标记为噪声点
        else:
            k=k+1
            cluster[j]=k
            for i in NeighborPts:
                if i not in fil:
                    gama.remove(i)
                    fil.append(i)
                    Ner_NeighborPts=findNeighbor(i,X,eps)
                    if len(Ner_NeighborPts) >= min_Pts:
                        for a in Ner_NeighborPts:
                            if a not in NeighborPts:
                                NeighborPts.append(a)
                    if (cluster[i]==-1):
                        cluster[i]=k
    return cluster

二、DBSCAN算法可视化的迭代算法实现

  国外有一个特别有意思的网站:https://www.naftaliharris.com/blog/visualizing-dbscan-clustering/它可以把我们DBSCAN的迭代过程动态图画出来。
在这里插入图片描述
  如果minPoints参数设置再大一点,那么这个笑脸可能会更好看。没有颜色标注的就是圈不到的样本点,也就是离群点,DBSCAN聚类算法在检测离群点的任务上也有较好的效果。如果是传统的Kmeans聚类,我们也来看一下效果:
在这里插入图片描述

三、案例及使用

sklearn中DBSCAN算法使用

DBSCAN(eps=0.5, min_samples=5, metric='euclidean', algorithm='auto', leaf_size=30, p=None, n_jobs=1)

参数说明:

  • eps:两个样本之间的最大距离,即扫描半径
  • min_samples :作为核心点的话邻域(即以其为圆心,eps为半径的圆,含圆上的点)中的最小样本数(包括点本身)。
  • metric :度量方式,默认为欧式距离,还有metric=‘precomputed’(稀疏半径邻域图)
  • algorithm:近邻算法求解方式,有四种:‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’
  • leaf_size:叶的大小,在使用BallTree or cKDTree近邻算法时候会需要这个参数
  • n_jobs :使用CPU格式,-1代表全开
1、采用datasets中的鸢尾花数据集

首先我们先看一下,原始的数据集根据第2和第3列的特征的类别分布

import numpy as np
import sklearn.cluster as skc
from sklearn import metrics
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
#导入数据集
X=load_iris().data
plt.scatter(X[:, 2], X[:, 3],c=load_iris().target)
plt.show()

如图所示:
在这里插入图片描述
使用DBSCAN算法进行聚类,代码如下:

import numpy as np
import sklearn.cluster as skc
from sklearn import metrics
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
#导入数据集
X=load_iris().data
# plt.scatter(X[:, 2], X[:, 3],c=load_iris().target)
# plt.show()
# DBSCAN聚类
db= skc.DBSCAN(eps=0.9, min_samples=10).fit(X[:,2:3])
label_pred = db.labels_

plt.scatter(X[:, 2], X[:, 3],c=label_pred)
plt.show()

参数eps=0.9, min_samples=10的运行结果如下
在这里插入图片描述
eps=0.2, min_samples=4
在这里插入图片描述

2、采用大学生校园网的日志数据

  现有大学校园网的日志数据,290条大学生的校园网使用情况数据,数据包括用户ID,设备的MAC地址,IP地址,开始上网时间,停止上网时间,上网时长,校园网套餐等。利用已有数据,分析学生上网的模式。
数据集是如下图所示:
在这里插入图片描述
对学生上网时间进行聚类

import numpy as np
import sklearn.cluster as skc
from sklearn import metrics
import matplotlib.pyplot as plt

mac2id = dict()
onlinetimes = []
f = open('TestData.txt', encoding='utf-8')
for line in f:
    mac = line.split(',')[2]
    onlinetime = int(line.split(',')[6])
    starttime = int(line.split(',')[4].split(' ')[1].split(':')[0])
    if mac not in mac2id:
        mac2id[mac] = len(onlinetimes)
        onlinetimes.append((starttime, onlinetime))
    else:
        onlinetimes[mac2id[mac]] = [(starttime, onlinetime)]
real_X = np.array(onlinetimes).reshape((-1, 2))

X = real_X[:, 0:1]

db = skc.DBSCAN(eps=0.01, min_samples=20).fit(X)   # dbscan聚类操作
labels = db.labels_    # 获取聚类标签

print('Labels:')
print(labels)
raito = len(labels[labels[:] == -1]) / len(labels)    # 标签为-1的为噪声点
print('Noise raito:', format(raito, '.2%'))   # 打印噪声点比例

n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)

print('Estimated number of clusters: %d' % n_clusters_)
print("Silhouette Coefficient: %0.3f" % metrics.silhouette_score(X, labels))

for i in range(n_clusters_):
    print('Cluster ', i, ':')
    print(list(X[labels == i].flatten()))

plt.hist(X, 24)
plt.show()

结果如下图所示:
在这里插入图片描述
在这里插入图片描述
从结果可以看出,学生的上网时间被分为了6个类别,分别为:22点/23点/21点/20点/7点/8点

四、常用的评估方法:轮廓系数

  当没有数据的基准可用时,我们必须使用内在方法来评估聚类的质量。一般而言,内在方法通过考察簇的分离情况和簇的紧凑情况来评估聚类。许多内在方法都利用数据集的对象之间的相似性度量。
  聚类算法中最常用的评估方法——轮廓系数(Silhouette Coefficient),它结合内聚度和分离度两种因素。可以用来在相同原始数据的基础上用来评价不同算法、或者算法不同运行方式对聚类结果所产生的影响。
在这里插入图片描述

  • 计算样本 i i i到同簇其它样本到平均距离 a i a_{i} ai a i a_{i} ai越小,说明样本 i i i越应该被聚类到该簇(将 a i a_{i} ai称为样本 i i i到簇内不相似度)。

  • 计算样本i到其它某簇 C j C_{j} Cj的所有样本的平均距离 b i j b_{ij} bij,称为样本 i i i与簇 C j C_{j} Cj的不相似度。定义为样本i的簇间不相似度: b i = m i n ( b i 1 , b i 2 , . . . , b i k 2 ) b_{i}=min(b_{i1},b_{i2},...,b_{ik_{2}}) bi=min(bi1,bi2,...,bik2)

  • s i s_{i} si接近1,则说明样本i聚类合理

  • s i s_{i} si接近-1,则说明样本i更应该分类到另外的簇

  • s i s_{i} si近似为0,则说明样本i在两个簇的边界上

总结

  • DBSCAN不需要事先知道要形成的簇类的数量,通过参数自动得到簇数;
  • DBSCAN能够识别出噪声点。对离群点有较好的鲁棒性,甚至可以检测离群点;
  • 输入参数敏感,确定参数Eps , MinPts困难 ,若选取不当 ,将造成聚类质量下降;
  • 由于经典的DBSCAN算法中参数Eps和MinPts(全局性表征密度的参数)在聚类过程中是不变的,因此当各个类的密度不均匀,或类间的距离相差很大时,聚类的质量较差

参考资料:

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我理解了你的问题。以下是我给出的答案: 首先,DBSCAN是一种常用的密度聚类算法,它可以将一组数据分成若干个不同的簇,使得同一簇内的数据点彼此相似度较高,不同簇之间的数据点差异性较大。在这里,我将使用Python编程语言中的scikit-learn库来实现DBSCAN聚类,并使用matplotlib库进行可视化。 其次,为了演示DBSCAN聚类和可视化的效果,我将选择一个名为Iris的数据集。这个数据集包含了150个鸢尾花的样本,每个样本包含了4个特征:花萼长度、花萼宽度、花瓣长度以及花瓣宽度。这个数据集可以在scikit-learn库中直接获取。 接下来,我将给出Python代码实现DBSCAN聚类和可视化的过程。你可以按照以下步骤进行操作: 1. 导入所需的库: ```python from sklearn.datasets import load_iris from sklearn.cluster import DBSCAN import matplotlib.pyplot as plt ``` 2. 加载数据集: ```python data = load_iris() X = data.data ``` 3. 对数据进行DBSCAN聚类: ```python dbscan = DBSCAN(eps=0.5, min_samples=5).fit(X) ``` 4. 可视化聚类结果: ```python plt.scatter(X[:, 0], X[:, 1], c=dbscan.labels_) plt.xlabel('Sepal length') plt.ylabel('Sepal width') plt.show() ``` 运行以上代码,就可以得到一个可视化的DBSCAN聚类结果。这个结果将鸢尾花样本分成了若干个簇,并用不同颜色的点表示不同的簇。你可以根据需要对代码进行修改,以适应你自己的数据集。 需要注意的是,在DBSCAN算法中,eps和min_samples是两个重要的参数。eps表示聚类的半径,min_samples表示一个簇中最少需要有多少个样本点。你需要根据自己的数据集,调整这两个参数以获得更好的聚类效果。 希望这个回答能够帮到你!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值