我们先试着了解一下DBSCAN基于密度的聚类的一些基本知识,下图总结了基本概念。
让我们首先创建一个将使用 DBSCAN 进行聚类的示例 2D 数据集。下图显示了数据集的外观。
import numpy as np
import matplotlib.pylab as plt
from sklearn.cluster import DBSCAN
X_train = np.array([[60,36], [100,36], [100,70], [60,70],
[140,55], [135,90], [180,65], [240,40],
[160,140], [190,140], [220,130], [280,150],
[200,170], [185, 170]])
plt.scatter(X_train[:,0], X_train[:,1], s=200)
plt.show()

现在让我们使用scikit-learn
DBSCAN 的实现来集群:
eps = 45
min_samples = 4
db = DBSCAN(eps=eps, min_samples=min_samples).fit(X_train)
labels = db.labels_
labels
# [ 0, 0, 0, 0, 0, 0, 0, -1, 1, 1, 1, -1, 1, 1]
db.core_sample_indices_
# [ 1, 2, 4, 9, 12, 13]
从以上结果可以看出
- 算法找到了6个核心点
- 找到了 2 个聚类(标签为 0、1)和几个异常值(噪声点)。
让我们使用以下代码片段可视化集群:
def dist(a, b):
return np.sqrt(np.sum((a - b)**2))
colors = ['r', 'g', 'b', 'k']
for i in range(len(X_train)):
plt.scatter(X_train[i,0], X_train[i,1],
s=300, color=colors[labels[i]],
marker=('*' if i in db.core_sample_indices_ else 'o'))
for j in range(i+1, len(X_train)):
if dist(X_train[i], X_train[j]) < eps:
plt.plot([X_train[i,0], X_train[j,0]], [X_train[i,1], X_train[j,1]], '-', color=colors[labels[i]])
plt.title('Clustering with DBSCAN', size=15)
plt.show()
- 簇 0 中的点为红色
- 簇 1 中的点为绿色
- 异常点为黑色
- 核心点用'*'标记。
- 如果两个点在 ϵ-nbd 内,则它们由一条边连接。

最后,让我们实现predict()
预测新数据点聚类的方法。实施基于以下几点:
为了使新点x属于一个簇,它必须是从簇中的一个核心点直接密度可达的。
我们将计算离集群最近的核心点,如果它与x的距离在 ε 之内,我们将返回核心点的标签,否则点x将被声明为噪声点(离群点)。
请注意,这与训练算法不同,因为我们不再允许任何点成为新的核心点(即核心点的数量是固定的)。
接下来的代码片段就是predict()
基于上面的思路实现的功能
def predict(db, x):
dists = np.sqrt(np.sum((db.components_ - x)**2, axis=1))
i = np.argmin(dists)
return db.labels_[db.core_sample_indices_[i]] if dists[i] < db.eps else -1
X_test = np.array([[100, 100], [160, 160], [60, 130]])
for i in range(len(X_test)):
print('test point: {}, predicted label: {}'.format(X_test[i],
predict(db, X_test[i])))
# test point: [100 100], predicted label: 0
# test point: [160 160], predicted label: 1
# test point: [ 60 130], predicted label: -1
下一个动画展示了如何使用predict()
上面定义的函数标记几个新的测试点。
