【机器学习】DBSCAN聚类算法——原理、参数调优与实战
DBSCAN聚类算法:从原理到参数调优实战
- 简介
- 一、DBSCAN 相关概念
- 核心概念图解
- 核心术语详解
- 算法实现流程
- 二、DBSCAN 的 API
- 核心参数说明
- 三、案例分析
- 1. 导入所需库
- 2. 数据读取与标准化
- 3. 数据准备
- 4. DBSCAN 参数调优
- 5. 确定最佳参数并输出结果
- 总结
- 关键参数调优建议
简介
本次我们将聚焦于一款极具特色的聚类算法——DBSCAN。相较于 K-means 等需要预先指定簇数量的算法,DBSCAN 以其"无监督自适应"的特性,在聚类领域占据着不可替代的地位。
在这一课中,我们会深入剖析 DBSCAN 算法的核心原理。你将了解到它如何通过"密度可达"和"核心对象"等关键概念,自动发现数据集中任意形状的簇,还能识别出那些不属于任何簇的噪声点。这一特性让它在处理非凸形状、存在噪声的数据时,展现出远超传统聚类算法的优势。
一、DBSCAN 相关概念
核心概念图解
DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的空间聚类算法。它将簇定义为密度相连的点的最大集合,能够将具有足够高密度的区域划分为簇,并在噪声数据中发现任意形状的聚类。
核心术语详解
| 术语 | 定义 |
|---|---|
| 核心对象(Core Point) | 如果某个点的 Eps 邻域内包含的样本数量 ≥ MinPts,则该点为核心对象 |
| Eps 邻域 | 给定对象半径 Eps 内的区域,即以该点为中心、Eps 为半径的圆形区域 |
| 直接密度可达 | 如果点 p 在点 q 的 Eps 邻域内,且 q 是核心对象,则称 p 从 q 直接密度可达 |
| 密度可达 | 存在一个点链 p₁, p₂, …, pₙ,使得每个点都从上一个点直接密度可达 |
| 边界点(Border Point) | 在某个簇内,但自身不是核心对象的点 |
| 离群点(Outlier / Noise) | 既不是核心对象也不是边界点,不属于任何簇的点 |
算法实现流程
- 输入数据集
- 指定半径 Eps
- 指定密度阈值 MinPts
- 遍历所有点,标记核心对象
- 对每个核心对象,找出其密度可达的所有点,形成簇
- 将不在任何簇中的点标记为噪声
二、DBSCAN 的 API
classsklearn.cluster.DBSCAN(eps=0.5,min_samples=5,metric='euclidean',metric_params=None,algorithm='auto',leaf_size=30,p=None,n_jobs=None)核心参数说明
| 参数 | 说明 |
|---|---|
| eps | 邻域半径,决定了一个点的邻域范围,默认 0.5 |
| min_samples | 构成核心点所需的最少样本数(密度阈值),默认 5 |
| metric | 距离度量方式,默认 ‘euclidean’(欧氏距离) |
| metric_params | 度量函数的额外参数,默认 None |
| algorithm | 近邻搜索算法,‘auto’ 表示自动选择(ball_tree / kd_tree / brute) |
| leaf_size | 构建 BallTree 或 KDTree 时的叶子节点大小,默认 30 |
| p | 闵可夫斯基距离的阶数(p=2 为欧氏距离,p=1 为曼哈顿距离) |
| n_jobs | 并行计算的 CPU 核心数,-1 表示使用所有核心 |
三、案例分析
1. 导入所需库
importpandasaspdfromsklearn.clusterimportDBSCANfromsklearn.preprocessingimportStandardScalerfromsklearn.metricsimportadjusted_rand_score,normalized_mutual_info_scoreimportnumpyasnp2. 数据读取与标准化
# 读取训练集和测试集数据data_train=pd.read_csv("datingTestSet2.txt",sep='\t',encoding='utf-8',engine='python',header=None)data_test=pd.read_csv("datingTestSet1.txt",sep='\t',encoding='utf-8',engine='python',header=None)# 标准化处理(DBSCAN 基于距离,必须进行标准化)scaler=StandardScaler()data_train.iloc[:,:-1]=scaler.fit_transform(data_train.iloc[:,:-1])data_test.iloc[:,:-1]=scaler.transform(data_test.iloc[:,:-1])3. 数据准备
x_train=data_train.iloc[:,:-1]# 训练集特征x_test=data_test.iloc[:,:-1]# 测试集特征y_train_true=data_train.iloc[:,-1]# 训练集真实标签y_test_true=data_test.iloc[:,-1]# 测试集真实标签4. DBSCAN 参数调优
# 测试不同的 eps 参数scores=[]eps_param_range=[0.09,0.1,0.2,0.3,0.4,0.5,0.6]forepsineps_param_range:dbscan=DBSCAN(eps=eps,min_samples=2)train_labels=dbscan.fit_predict(x_train)# 忽略噪声点(标签为 -1)进行评估mask=train_labels!=-1ifnp.sum(mask)>0:ari=adjusted_rand_score(y_train_true[mask],train_labels[mask])nmi=normalized_mutual_info_score(y_train_true[mask],train_labels[mask])score_mean=(ari+nmi)/2scores.append(score_mean)print(f"eps ={eps},平均得分 (ARI+NMI)/2 ={score_mean:.4f}")else:print(f"eps ={eps},所有样本均被标记为噪声")scores.append(-1)5. 确定最佳参数并输出结果
# 选择最佳 epsbest_eps=eps_param_range[np.argmax(scores)]print(f"最优 eps 参数:{best_eps}")# 使用最佳参数重新训练best_dbscan=DBSCAN(eps=best_eps,min_samples=2)train_labels=best_dbscan.fit_predict(x_train)print("训练集聚类标签:\n",train_labels)# 对测试集进行聚类test_labels=best_dbscan.fit_predict(x_test)print("测试集聚类标签:\n",test_labels)总结
DBSCAN 的优势
无需预先指定簇数量:自动发现数据中的聚类结构
可发现任意形状的簇:不同于 K-means 只能发现球形簇
具有噪声过滤能力:能自动识别并剔除离群点
关键参数调优建议
| 参数 | 调优方法 |
|---|---|
| eps | 使用 k-distance 图辅助确定;或通过网格搜索结合评估指标选择 |
| min_samples | 一般取数据维度的 2 倍或更大;数据量较大时可适当增加 |
