目录
- 一、DBSCAN 参数
- 二、参数选择方法
-
- 2.1 MinPts 的经验选取
- 2.2 Eps 的选取 —— K-Distance(k-距离)图法
- 三、Python 实现:参数选择与离群值检测
-
- 3.1 导包与生成示例数据
- 3.2 绘制 K-Distance 图确定 Eps
- 3.3 执行 DBSCAN 聚类与离群值检测
- 3.4 可视化聚类与离群值
- 四、关键注意事项与调参建议
- 五、小结
- 六、参考链接
一、DBSCAN 参数
| Eps(ε) | 邻域半径 | 若两点距离 ≤ Eps,则认为互为邻域 |
| MinPts | 核心点最少样本数 | 某点的 Eps 邻域内至少含 MinPts 个点(含自身),才被标记为核心点 |
- 核心点(Core Point):Eps 邻域内样本数 ≥ MinPts
- 边界点(Border Point):落在某核心点的 Eps 邻域内,但自身不满足 MinPts
- 噪声点(Noise / Outlier):既非核心点也非边界点,DBSCAN 标记为 -1
二、参数选择方法
2.1 MinPts 的经验选取
推荐经验公式:
MinPts = D + 1 (D 为数据特征维度)
更保守的做法是取:
MinPts = 2 × D – 1
- 二维数据(D=2):MinPts 常取 3~5,常用 MinPts = 4
- 噪声较多或数据量较大时,可适当增大 MinPts 以减少假簇
注意:k-distance 图中的 k = MinPts – 1
2.2 Eps 的选取 —— K-Distance(k-距离)图法
步骤:
原理: 拐点之前是密集区域的点,之后是稀疏或孤立点。拐点距离反映了"正常密度区域的最大合理邻域半径"。
三、Python 实现:参数选择与离群值检测
3.1 导包与生成示例数据
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN
from sklearn.neighbors import NearestNeighbors
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_moons
# 固定随机种子,保证可复现
np.random.seed(2021)
# 生成半月形非线性数据(含一定噪声)
X, y_true = make_moons(n_samples=400, noise=0.07, random_state=42)
# DBSCAN 对量纲敏感,务必标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
3.2 绘制 K-Distance 图确定 Eps
def plot_k_distance(X, k, figsize=(8, 5)):
"""
绘制 k-distance 图辅助选择 DBSCAN 的 eps
Parameters:
X: 标准化后的特征矩阵
k: 取 MinPts – 1(即计算第 k 近邻距离)
"""
nbrs = NearestNeighbors(n_neighbors=k + 1, algorithm='auto').fit(X)
distances, _ = nbrs.kneighbors(X)
# 第 k 列 = 第 k 近邻距离(第 0 列是自身)
k_dist = np.sort(distances[:, k])[::–1]
plt.figure(figsize=figsize)
plt.plot(k_dist)
plt.xlabel("Points sorted by distance (descending)")
plt.ylabel(f"{k}-distance (distance to {k}th NN)")
plt.title("K-Distance Graph — Select Eps at the 'Elbow'")
plt.grid(alpha=0.4)
plt.show()
return k_dist
# 二维数据:MinPts 建议取 4 → k = MinPts – 1 = 3
k = 3
k_dist = plot_k_distance(X_scaled, k=k)

📌 观察图中拐点位置,出现在约 0.25,则取 eps=0.25。
3.3 执行 DBSCAN 聚类与离群值检测
# 根据 k-distance 图选定的参数
eps = 0.25
min_samples = k + 1 # = 4
dbscan = DBSCAN(
eps=eps,
min_samples=min_samples,
metric='euclidean',
algorithm='auto'
)
labels = dbscan.fit_predict(X_scaled)
# 离群值标记:label == -1
is_outlier = labels == –1
n_clusters = len(set(labels)) – (1 if –1 in labels else 0)
n_outliers = np.sum(is_outlier)
print(f"发现的簇数: {n_clusters}")
print(f"检测到的离群值数量: {n_outliers}")
print(f"核心样本数: {len(dbscan.core_sample_indices_)}")
3.4 可视化聚类与离群值
plt.figure(figsize=(8, 6))
# 正常点按簇上色,离群值用红色 × 标记
unique_labels = np.unique(labels)
colors = plt.cm.viridis(np.linspace(0, 1, len(unique_labels)))
for label, color in zip(unique_labels, colors):
mask = labels == label
if label == –1:
# 噪声点 / 离群值
plt.scatter(
X_scaled[mask, 0], X_scaled[mask, 1],
c='red', marker='x', s=50,
label=f'Outlier ({np.sum(mask)})'
)
else:
plt.scatter(
X_scaled[mask, 0], X_scaled[mask, 1],
c=[color], s=30,
label=f'Cluster {label}'
)
plt.title(f"DBSCAN Outlier Detection (eps={eps}, MinPts={min_samples})")
plt.xlabel("Feature 1 (standardized)")
plt.ylabel("Feature 2 (standardized)")
plt.legend(loc='best', fontsize=9)
plt.grid(alpha=0.3)
plt.show()

四、关键注意事项与调参建议
五、小结
- MinPts 按维度经验取 D+1 或 2D-1
- Eps 通过 k-distance(k = MinPts – 1)图的拐点确定
- DBSCAN 中 label == -1 即为检测到的离群值/异常点
- sklearn 的 NearestNeighbors + DBSCAN 即可完整覆盖参数选择 → 聚类 → 异常检测的流程
六、参考链接
机器学习 聚类篇——DBSCAN的参数选择及其应用于离群值检测




