首先,我们生成一组随机数据,为了体现 DBSCAN 在非凸数据的聚类优点,我们生成了三簇数据,两组是非凸的。代码如下:
- import numpy as np
- import matplotlib.pyplot as plt
- from sklearn import datasets
- %matplotlib inline
- X1, y1=datasets.make_circles(n_samples=5000, factor=.6,
- noise=.05)
- X2, y2 = datasets.make_blobs(n_samples=1000, n_features=2, centers=[[1.2,1.2]], cluster_std=[[.1]],
- random_state=9)
- X = np.concatenate((X1, X2))
- plt.scatter(X[:, 0], X[:, 1], marker='o')
- plt.show()
可以直观看看我们的样本数据分布输出:
首先我们看看 K-Means 的聚类效果,代码如下:
- from sklearn.cluster import KMeans
- y_pred = KMeans(n_clusters=3, random_state=9).fit_predict(X)
- plt.scatter(X[:, 0], X[:, 1], c=y_pred)
- plt.show()
K-Means 对于非凸数据集的聚类表现不好,从上面代码输出的聚类效果图可以明显看出,输出图如下:
那么如果使用 DBSCAN 效果如何呢?我们先不调参,直接用默认参数,看看聚类效果, 代码如下:
- from sklearn.cluster import DBSCAN
- y_pred = DBSCAN().fit_predict(X)
- plt.scatter(X[:, 0], X[:, 1], c=y_pred)
- plt.show()
发现输出让我们很不满意,DBSCAN 居然认为所有的数据都是一类!输出效果图如下:
怎么办?看来我们需要对 DBSCAN 的两个关键的参数 eps 和 min_samples 进行调参!从上图我们可以发现,类别数太少,我们需要增加类别数,那么我们可以减少 $\epsilon$- 邻域的大小,默认是 0.5,我们减到 0.1 看看效果。代码如下:
- y_pred = DBSCAN(eps = 0.1).fit_predict(X)
- plt.scatter(X[:, 0], X[:, 1], c=y_pred)
- plt.show()
对应的聚类效果图如下:
可以看到聚类效果有了改进,至少边上的那个簇已经被发现出来了。此时我们需要继续调参增加类别,有两个方向都是可以的,一个是继续减少 eps,另一个是增加 min_samples。我们现在将 min_samples 从默认的 5 增加到 10,代码如下:
- y_pred = DBSCAN(eps = 0.1, min_samples = 10).fit_predict(X)
- plt.scatter(X[:, 0], X[:, 1], c=y_pred)
- plt.show()
输出的效果图如下:
可见现在聚类效果基本已经可以让我们满意了。
上面这个例子只是帮大家理解 DBSCAN 调参的一个基本思路,在实际运用中可能要考虑很多问题,以及更多的参数组合,希望这个例子可以给大家一些启发。
来源: