密度聚类(Density-based Clustering)假设聚类结构能够通过样本分布的紧密程度来确定。DBSCAN是常用的密度聚类算法,它通过一组邻域参数( ϵ , MinPts )来描述样本分布的紧密程度。给定数据集 D ={ x⃗ 1,x⃗ 2,x⃗ 3,...,x⃗ N },数据集属性定义如下。
ϵ -邻域: Nϵ(x⃗ i) ={ x⃗ j∈D|distance(x⃗ i,x⃗ j) ≤ϵ }, Nϵ(x⃗ i) 包含了样本集 D 中与 x⃗ i 距离不大于 ϵ 的所有样本。
核心对象core object:若| Nϵ(x⃗ i) | ≥MinPts ,则称 x⃗ i 是一个核心对象。即:若 x⃗ i 的 ϵ -邻域中至少包含 MinPts 个样本,则称 x⃗ i 是一个核心对象。
密度直达directly density-reachable:若 x⃗ i 是一个核心对象,且 x⃗ j∈ Nϵ(x⃗ i) ,则称 x⃗ j 由 x⃗ i 密度直达,记作 x⃗ i –> x⃗ j 。
密度可达density-reachable:对于 x⃗ i 和 x⃗ j ,若存在样本序列( p⃗ 0,p⃗ 1,p⃗ 2,...,p⃗ m,p⃗ m+1 ),其中 p⃗ 0 = x⃗ i , p⃗ m+1 = x⃗ j , p⃗ s∈D,s=1,2,...,m 。如果 p⃗ s+1 由 p⃗ s,s=1,2,...,m 密度直达,则称 x⃗ j 由 x⃗ i 密度可达,记作 x⃗ i ~> x⃗ j 。
DBSCAN算法的定义:给定邻域参数( ϵ , MinPts ),一个簇 C⊆D 是满足下列性质的非空样本子集:
DBSCAN算法的思想:若 x⃗ 为核心对象,则 x⃗ 密度可达的所有样本组成的集合X={ x⃗ ∗∈D|x⃗ ~> x⃗ ∗ },可以证明 X 就是满足连接性与最大性的簇。于是DBSCAN算法首选任选数据集中的一个核心对象作为种子 seed ,再由此出发确定相应的聚类簇。
下面给出DBSCAN算法:
输入
输出:簇划分 C ={ C1,C2,...,Ck }
DBSCAN 是 sciki−kearn 提供的密度聚类算法模型,其原型为:
class sklearn.cluster.DBSCAN(eps=0.5,min_samples=5,metric='euclidean',algorithm='auto',leaf_size=30,p=None,random_state=None)
参数
属性
方法
#导包
from sklearn import cluster
from sklearn.metrics import adjusted_rand_score
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets.samples_generator import make_blobs
from sklearn import mixture
from sklearn.svm.libsvm import predict
#产生数据
def create_data(centers,num=100,std=0.7):
X,labels_true = make_blobs(n_samples=num,centers=centers, cluster_std=std)
return X,labels_true
"""
数据作图
"""
def plot_data(*data):
X,labels_true=data
labels=np.unique(labels_true)
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
colors='rgbycm'
for i,label in enumerate(labels):
position=labels_true==label
ax.scatter(X[position,0],X[position,1],label="cluster %d"%label),
color=colors[i%len(colors)]
ax.legend(loc="best",framealpha=0.5)
ax.set_xlabel("X[0]")
ax.set_ylabel("Y[1]")
ax.set_title("data")
plt.show()
#测试函数
def test_DBSCAN(*data):
X,labels_true = data
clst = cluster.DBSCAN();
predict_labels = clst.fit_predict(X)
print("ARI:%s"%adjusted_rand_score(labels_true,predict_labels))
print("Core sample num:%d"%len(clst.core_sample_indices_))
#结果
ARI:0.330307120902
Core sample num:991
其中 ARI 指标为0.330307120902,该值越大越好,DBSCAN根据密度,将原始数据集划分为991个簇。
下面考察 ϵ 参数的影响:
def test_DBSCAN_epsilon(*data):
X,labels_true = data
epsilons = np.logspace(-1,1.5)
ARIs=[]
Core_nums = []
for epsilon in epsilons:
clst = cluster.DBSCAN(eps=epsilon)
predicted_labels = clst.fit_predict(X)
ARIs.append(adjusted_rand_score(labels_true,predicted_labels))
Core_nums.append(len(clst.core_sample_indices_))
fig = plt.figure(figsize=(10,5))
ax = fig.add_subplot(1,2,1)
ax.plot(epsilons,ARIs,marker = '+')
ax.set_xscale('log')
ax.set_xlabel(r"$\epsilon$")
ax.set_ylim(0,1)
ax.set_ylabel('ARI')
ax = fig.add_subplot(1,2,2)
ax.plot(epsilons,Core_nums,marker='o')
ax.set_xscale('log')
ax.set_xlabel(r"$\epsilon$")
ax.set_ylabel('Core_num')
fig.suptitle("DBSCAN")
plt.show()
centers = [[1,1],[1,2],[2,2],[10,20]]
X,labels_true = create_data(centers,1000,0.5)
test_DBSCAN_epsilon(X,labels_true)
ϵ 参数的影响结果如上图所示:
可以看到 ARI 指数随着 ϵ 的增长,先上升后保持平稳,最后悬崖式下降。悬崖式下降是因为我们产生的训练样本的间距比较小,最远的两个样本之间的距离不超过30,当 ϵ 过大时,所有的点都在一个邻域中。
样本核心数量随着 ϵ 的增长而上升,这是因为随着 ϵ 的增长,样本点的邻域在扩展,则样本点邻域中的样本会增多,这就产生了更多满足条件的核心样本点。但是样本集中的样本数量有限,因此核心样本点的数量增长到一定数目后会趋于稳定。
下面接着考察 MinPts 参数的影响:
def test_DBSCAN_min_samples(*data):
X,labels_true=data
min_samples=range(1,100)
ARIs=[]
Core_nums=[]
for num in min_samples:
clst=cluster.DBSCAN(min_samples=num)
predicted_labels=clst.fit_predict(X)
ARIs.append(adjusted_rand_score(labels_true, predicted_labels))
Core_nums.append(len(clst.core_sample_indices_))
fig=plt.figure(figsize=(10,5))
ax=fig.add_subplot(1,2,1)
ax.plot(min_samples,ARIs,marker='+')
ax.set_xlabel("min_samples")
ax.set_ylim(0,1)
ax.set_ylabel('ARI')
ax=fig.add_subplot(1,2,2)
ax.plot(min_samples,Core_nums,marker='o')
ax.set_xlabel("min_samples")
ax.set_ylabel('Core_nums')
fig.suptitle("DBSCAN")
plt.show()
centers = [[1,1],[1,2],[2,2],[10,20]]
X,labels_true = create_data(centers,1000,0.5)
test_DBSCAN_min_samples(X,labels_true)
MinPts 参数的影响结果如下:
可以看出 ARI 指数随着 MinPts 的增长,平稳地下降。而核心样本数量随着 MinPts 的增长基本呈线性下降,这是因为随着 MinPts 的增长,样本点的邻域中必须包含更多的样本才能使它成为一个核心点。因此产生的样本点数量越来越少。
有关 ARI ,请参考:
聚类的有效性指标