1 什么是DBSCAN?

        DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的聚类算法。与 K-Means 不同,DBSCAN 不要求用户预先指定聚类的数量,它通过密度来定义聚类的边界。具体来说,DBSCAN 尝试找到密度较高的区域,并将这些区域归为同一类,密度较低的区域则被标记为噪声。DBSCAN 可以发现任意形状的聚类,并且能够有效处理噪声。它不需要预设聚类的数量,适用于那些包含离群点和密度不均的数据集。

2 核心原理 

邻域概念:DBSCAN 算法基于数据点之间的距离来定义邻域。对于给定的数据点,以p为中心,半径为ε(称为邻域半径)的圆形区域称为的邻域。

核心点判定:如果一个数据点的邻域内包含的数据点数量(包括本身)不少于给定的最小点数,那么被称为核心点。

边界点和噪声点判定:如果一个点不是核心点,但它落在某个核心点的- 邻域内,那么是边界点;如果一个点既不是核心点也不是边界点,那么它是噪声点。

聚类形成:DBSCAN 算法会不断寻找新的核心点,每个核心点及其密度相连的点构成一个独立的聚类。不同的聚类之间是相互独立的,它们不会因为算法的执行而合并(除非在参数设置不合理的情况下,如邻域半径过大等)。这样,通过对所有数据点的扫描和判断,数据集中的点被划分成了不同的聚类和噪声点,从而完成了聚类的形成过程  。  

参数调优的策略:

为了调优DBSCAN的参数,可以采取以下策略:

  1. 利用k-distance图选择ε:计算每个点的k距离,并绘制k-distance图,寻找拐点来选择ε。
  2. 交叉验证法:在不同的最小点数MinPts值和领域半径ε值下运行DBSCAN,并计算聚类的稳定性。选择最能在多个实验中产生一致结果的参数。
  3. 视觉化:通过二维或三维散点图展示不同参数下的聚类效果,直观观察聚类质量。

3 聚类过程

步骤一:初始化

1.确定邻域半径和最小点数。邻域半径决定了以某个数据点为中心的邻域范围大小,最小点数则用于判定一个数据点是否为核心点。
2.标记所有数据点为未访问状态,以便后续在遍历过程中知晓哪些点已经被处理过,哪些还未处理。

步骤二:遍历数据点

1.随机选择一个未访问的数据点,标记为已访问。
2.根据刚才标记的数据点,计算的邻域。
3.如果是核心点,就创建一个新的聚类(可以用一个类别标识来表示这个聚类),把这个核心点以及它的邻域内所有还未被分配到任何聚类的点都加入到这个新创建的聚类当中。按照这样的方式不断递归地去查找和添加点,一直持续到再也没有新的数据点可以加入到这个聚类为止。
如果不是核心点,则是边界点或噪声点,暂时不处理。

步骤三:重复步骤二

直到所有数据点都被访问。此时,所有被标记为聚类的数据点构成了最终的聚类结果,剩下一直未被分配到聚类的点被标记为噪声点,从而完成整个数据集基于 DBSCAN 算法的聚类分析。

4 DBSCAN的优缺点

DBSCAN作为一种密度基的聚类方法,在许多应用场景中表现出了独特的优势,但也存在一定的缺点。以下是DBSCAN的优缺点分析:

优点

不需要预先指定聚类数量:与 K - Means 等聚类算法不同,DBSCAN 不需要预先知道数据集中应该有几个聚类,它能够自动发现数据中的聚类结构。

能够发现任意形状的聚类:由于它是基于密度的算法,所以可以很好地处理非凸形状的聚类,例如环形、S 形等复杂形状的聚类,而像 K - Means 等基于距离中心的算法在处理这类形状的聚类时会遇到困难。

能够识别噪声点:可以有效地将噪声点从数据集中分离出来,这对于数据清洗和异常检测等任务非常有用。

缺点

参数敏感:如前面提到的,算法的性能对邻域半径和最小点数这两个参数比较敏感,不合适的参数选择可能导致不理想的聚类结果。

计算复杂度高:在处理大规模数据集时,计算数据点之间的距离和邻域关系会消耗大量的计算资源和时间,特别是当数据集的维度较高时,计算复杂度会显著增加。

5 DBSCAN的适用场景与应用领域

DBSCAN 被广泛应用于地理信息系统(GIS)、图像处理、异常检测、市场分析等多个领域。它特别适用于以下场景:

空间数据聚类:如城市中的地理位置点聚类,或气候数据的空间分布分析。

图像处理:如图像分割,利用 DBSCAN 来区分不同的区域或对象。

异常检测:通过 DBSCAN 聚类时,可以标记那些无法归类的点作为异常点或噪声。

6 医疗预测实例

# 导入matplotlib.pyplot库用于绘图
import matplotlib.pyplot as plt

# 定义一个函数graph3d,用于绘制3D散点图
def graph3d(data, x, y, z):
    # 创建一个3D坐标轴的subplot
    ax = plt.figure().add_subplot(111, projection='3d')
    
    # 绘制散点图,x、y、z分别为数据的列名
    # s=10 设置点的大小,c='r' 设置点的颜色为红色,marker='.' 设置点的形状为小点
    ax.scatter(data[x], data[y], data[z], s=10, c='r', marker='.')
    
    # 设置x轴标签为列名x
    ax.set_xlabel(x)
    
    # 设置y轴标签为列名y
    ax.set_ylabel(y)
    
    # 设置z轴标签为列名z
    ax.set_zlabel(z)

# 显示绘制的图形
plt.show()

# 调用graph3d函数,传入数据集train和列名age, bmi, charges进行3D散点图绘制
graph3d(train, 'age', 'bmi', 'charges')

# 导入sklearn.cluster模块,用于聚类分析
import sklearn.cluster as cluster

# 定义dbscan函数,使用DBSCAN算法进行聚类
def dbscan(data, features=None):
    # 初始化DBSCAN聚类器,设置eps和min_samples参数
    clusterer = cluster.DBSCAN(eps=0.45, min_samples=10)
    
    # 默认情况下,使用整个数据集进行聚类
    x = data
    # 如果指定了特征列,则仅使用指定的列进行聚类
    if (features):
        x = data[features]
    
    # 使用DBSCAN进行聚类,fit_predict方法会返回每个样本的聚类标签
    y = clusterer.fit_predict(x.values)
    
    # 将聚类标签(y)添加到原始数据集,并命名为"type"
    data["type"] = y
    
    # 返回包含聚类标签的数据集
    return data

# 选择数据集中的"age", "bmi", "charges"列作为特征进行聚类
train1 = train[["age", "bmi", "charges"]].copy(deep=True)

# 对于"charges"特征,增加一个权重(乘以3),目的是拉长层间距离,可能是为了提高聚类效果
train1["charges"] *= 3

# 使用DBSCAN算法对train1数据集进行聚类,并将聚类结果存储到train中的"type"列
train["type"] = dbscan(train1)["type"]

# 输出train数据集中"type"列的唯一值,查看聚类结果
train["type"].unique()

# 导入matplotlib.pyplot库,用于绘图
import matplotlib.pyplot as plt

# 定义3D散点图绘制函数,显示不同聚类类型的3D分布
def graph3dc(train, x, y, z, type_name="type"):
    # 创建一个3D绘图的子图
    ax = plt.figure().add_subplot(111, projection = '3d')
    
    # 筛选出聚类类型为0的数据
    data = train[train[type_name] == 0]
    # 绘制聚类类型为0的数据,红色('r')的散点图,点大小为10
    ax.scatter(data[x], data[y], data[z], s=10, c='r', marker='.')
    
    # 筛选出聚类类型为1的数据
    data = train[train[type_name] == 1]
    # 绘制聚类类型为1的数据,绿色('g')的散点图,点大小为10
    ax.scatter(data[x], data[y], data[z], s=10, c='g', marker='.')
    
    # 筛选出聚类类型为2的数据
    data = train[train[type_name] == 2]
    # 绘制聚类类型为2的数据,蓝色('b')的散点图,点大小为10
    ax.scatter(data[x], data[y], data[z], s=10, c='b', marker='.')
    
    # 设置x轴标签
    ax.set_xlabel(x)
    # 设置y轴标签
    ax.set_ylabel(y)
    # 设置z轴标签
    ax.set_zlabel(z)
    
    # 显示图形
    plt.show()

# 调用graph3dc函数,绘制年龄、BMI和费用的3D散点图,根据聚类类型不同颜色显示
graph3dc(train, 'age', 'bmi', 'charges')

graph3dc(train, 'age', 'bmi', 'smoker')

调用了之前定义的 graph3dc 函数,并传入了以下参数:

train: 这是一个包含数据的 DataFrame,它包含了我们要进行分析和可视化的所有数据。train 中有多个列,包括 age(年龄)、bmi(身体质量指数)、smoker(是否吸烟)等。

'age': 这是我们要在 3D 图上显示的第一个维度,表示数据点的 age(年龄)。此列的数据会被作为 X 轴的坐标。

'bmi': 这是我们要在 3D 图上显示的第二个维度,表示数据点的 bmi(身体质量指数)。此列的数据会被作为 Y 轴的坐标。

'smoker': 这是我们要在 3D 图上显示的第三个维度,表示数据点的 smoker(是否吸烟)。此列的数据会被作为 Z 轴的坐标。该字段通常包含分类数据(如:'yes' 或 'no'),用于表示是否吸烟。
绘制出如下结果:

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐