基于密度的方法:DBSCAN
可视化网址:https://www.naftaliharris.com/blog/visualizing-dbscan-clustering/
DBSCAN = Density-Based Spatial Clustering of Applications with Noise
本算法将具有足够高密度的区域划分为簇,并可以发现任何形状的聚类
几个概念
𝛆邻域:给定对象半径𝜀内的区域称为该对象的𝜀邻域。
核心对象:如果给定 𝜀 邻域内的样本点数大于等于Minpoints,则该对象为核心对象。
直接密度可达:给定一个对象集合D,如果p在q的𝜀邻域内, 且q是一个核心对象,则我们说对象p从q触发是直接密度可达的(directly density-reachable)。
密度可达:集合D,存在一个对象链p1,p2…pn, p1=q, pn=p,pi+1是从pi关于𝜀和Minpoints直接密度可达,则称点p是从q关于𝜀和Minpoints密度可达的。
密度相连:集合D存在点o,使得点p、q是从o关于𝜀和Minpoints密度可达的,那么点p、q是关于𝜀和Minpoints密 度相连的。
DBSCAN算法思想
1.指定合适的𝜀和Minpoints。
2.计算所有的样本点,如果点p的𝜀邻域里有超过Minpoints个点,则创建一个以p为核心点的新族。
3.反复寻找这些核心点直接密度可达(之后可能是密度可达)的点,将其加入到相应的簇,对于核心点发生“密度相连”状况的簇,给予合并。
4.当没有新的点可以被添加到任何簇时,算法结束。
DBSCAN分析
缺点:
• 当数据量增大时,要求较大的内存支持I/O消耗也很大。 • 当空间聚类的密度不均匀、聚类间距差相差很大时,聚 类质量较差。
DBSCAN和K-MEANS比较:
• DBSCAN不需要输入聚类个数。
• 聚类簇的形状没有要求。
• 可以在需要时输入过滤噪声的参数。
代码实现
案例一
导入包
from sklearn.cluster import DBSCAN
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
载入数据
data = pd.read_csv("kmeans.txt", delimiter=" ")
训练模型
# eps距离阈值,min_samples核心对象在eps领域的样本数阈值
model = DBSCAN(eps=1.5, min_samples=4)
model.fit(data.iloc[:,:2])
预测结果
result = model.fit_predict(data.iloc[:,:2])
result
array([ 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, -1, 1, 3, 0,
1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1,
2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2,
3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2], dtype=int64)
画图展示聚类结果
# 画出各个数据点,用不同颜色表示分类
mark = ['or', 'ob', 'og', 'oy', 'ok', 'om']
for i in range(len(data)):
plt.plot(data.iloc[i,0], data.iloc[i,1], mark[result[i]])
plt.show()
案例二
导入包
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
利用datasets创建数据
x1, y1 = datasets.make_circles(n_samples=2000, factor=0.5, noise=0.05)
x2, y2 = datasets.make_blobs(n_samples=1000, centers=[[1.2,1.2]], cluster_std=[[.1]])
x = np.concatenate((x1, x2))
plt.scatter(x[:, 0], x[:, 1], marker='o')
plt.show()
x1是一个两维的坐标,y1是0或者1的一个列表(x2,y2同理)
先建立kMeans聚类算法,聚为3类
from sklearn.cluster import KMeans
y_pred = KMeans(n_clusters=3).fit_predict(x)
plt.scatter(x[:, 0], x[:, 1], c=y_pred)
plt.show()
显然结果不好。
建立DBSCAN算法,采用默认参数
from sklearn.cluster import DBSCAN
y_pred = DBSCAN().fit_predict(x)
plt.scatter(x[:, 0], x[:, 1], c=y_pred)
plt.show()
默认参数,结果聚为1类,与想象中的有差别。
调整DBSCAN的参数eps的值
y_pred = DBSCAN(eps = 0.2).fit_predict(x)
plt.scatter(x[:, 0], x[:, 1], c=y_pred)
plt.show()
调整DBSCAN的参数eps和 min_samples的值
y_pred = DBSCAN(eps = 0.2, min_samples=50).fit_predict(x)
plt.scatter(x[:, 0], x[:, 1], c=y_pred)
plt.show()
这样的聚类效果要好于前面的。