DBSCAN(Density-Based Spatial Clustering of Applications with Noise) 为一种基于密度的聚类算法,本文主要介绍了DBSCAN算法的原理和参数选择方法,并实现了一个离群值检测案例,供读者参考。
DBSCAN算法主要有两个参数:
领域半径:Eps;
成为核心对象的在领域半径内的最少点数:MinPts。
以上两个参数都会在下面的概念介绍中提到。
Eps领域(Eps-neighborhood of a point)
点p的Eps邻域,记为NEps(p),定义为NEps(p)= {q∈D | dist(p,q)≤Eps}。
核心对象 (core points)
如果给定对象Eps领域内的样本点数大于等于MinPts,则称该对象为核心对象。
直接密度可达(directly density-reachable)
若:
1) p∈ NEps(q)
2)|NEps(q)| ≥ MinPts
则称对象p从核心对象q是直接密度可达的。
密度可达(density-reachable)
对于对象p1,p2, …, pn;
令p1= q, pn = p。
若pi+1是从pi直接密度可达的,则称p是从q密度可达的。
密度相连(density-connected)
对于点p和点q,若点p点q都是从点o密度可达的,则称点p和点q密度相连。
簇(cluster)
对于数据集D,若C是其中一个簇,C中的点需要满足以下两个条件:
1)∀ p, q,如果 p∈ C且q 是从p密度可达的,则 q∈ C。
2)∀ p, q ∈ C,p和q是密度相连的。
噪音(noise)
不属于任何簇的点为噪音数据。
M i n P t s = k + 1 MinPts = k+1 MinPts=k+1
链接: 参考我的另一篇博客.
import numpy as np
from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN
np.random.seed(2021)
data = np.ones([1005,2])
data[:1000] = make_moons(n_samples=1000,noise=0.05,random_state=2022)[0]
data[1000:] = [[-1,-0.5],
[-0.5,-1],
[-1,1.5],
[2.5,-0.5],
[2,1.5]]
print(data.shape)
plt.scatter(data[:,0],data[:,1],color="c")
plt.show()
def select_MinPts(data,k):
k_dist = []
for i in range(data.shape[0]):
dist = ((data[i] - data).sum(axis=1)**0.5)
dist.sort()
k_dist.append(dist[k])
return np.array(k_dist)
k = 3 # 此处k取 2*2 -1
k_dist = select_MinPts(data,k)
k_dist.sort()
plt.plot(np.arange(k_dist.shape[0]),k_dist[::-1])
# 由拐点确定邻域半径
eps = k_dist[::-1][15]
plt.scatter(15,eps,color="r")
plt.plot([0,15],[eps,eps],linestyle="--",color = "r")
plt.plot([15,15],[0,eps],linestyle="--",color = "r")
plt.show()
dbscan_model = DBSCAN(eps=eps,min_samples=k+1)
label = dbscan_model.fit_predict(data)
print(label)
[ 0 0 0 ... -1 -1 -1]
class_1 = []
class_2 = []
noise = []
for index,value in enumerate(label):
if value == 0:
class_1.append(index)
elif value == 1:
class_2.append(index)
elif value == -1:
noise.append(index)
plt.scatter(data[class_1,0],data[class_1,1],color="g",label="class 1")
plt.scatter(data[class_2,0],data[class_2,1],color="b",label = "class 2")
plt.scatter(data[noise,0],data[noise,1],color="r",label = "noise")
plt.legend()
plt.show()
by CyrusMay 2021 02 03
你和我背着空空的书包
逃出名为日常的监牢
忘了要长大
忘了要变老
忘了时间有脚
——————五月天(好好)——————