核心思想:使用一个点邻域内的邻居点数量衡量该点所在空间的密度,
找出形状不规则的聚类,不需要先确定聚类数量。
DBSCAN聚类需要两个参数:Eps,确定邻域范围(半径);MinPts,核心点的阈值(密度数量)。
核心点对应稠密区局内部的点,边界点对应稠密区边缘点,噪音点在稀疏区域。
密度:在某距离内含有对象的最小数目。
核心对象:如果一个对象的eps邻域内至少包含MinPt个对象,则称该对象是核心对象。
直接密度可达:给定集合D,如果 p 在 q 的eps邻域内,且 q 是一个核心对象,
则 p 是从 q 直接密度可达的。
eps 为一个超球体的半径,Minp就是这个超球体内的点。
密度可达:q 和 p 之间,有样本序列p1,p2,p3,……,pn, 其中p1=q, pn=p,
若Pi+1是由Pi直接密度可达的,则 p 是由 q 关于eps 和 MinPts 密度可达的。
即 p 不在核心对象 q 的邻域内,但在 q 邻域内点的邻域内。
DBSCAN算法:从选定的核心点出发,不断向密度可达的区域扩张,
得到含有核心点和边界点的最大化区域,区域中任意两点密度相连。
DBSCAN 需要访问 X 所有节点,复杂度取决于区域查询(获取节点的邻域)的次数,时间复杂度O(N^2);通常需要用 N 阶距离矩阵存储距离,避免重复计算,需要O(N^2)空间开销。
优点:无需指定聚类数目;可发现任意形状的聚类;可找到噪音,且对噪音敏感;
只有两个参数;不依赖于节点的遍历顺序。
缺点:DBSCAN聚类效果依赖于距离公式的选取,常用欧几里得距离;
但对高维数据,由于维度灾难,距离的度量变的不重要了。
不适用于数据集中密度差异很大的情况,此时参数很难选择。
参数选择方法:
半径:K距离可帮助设定半径r,就是找到突变点;可先选择一个点,计算到其它所有点的距离,
从小到大排序,找到距离间差异最大的,使用前一个距离作为半径。
例如计算得到的距离为 d1, d2, d3, d4, d5,其中d2和d3间差异最大,则使用 d2 作为半径。
k距离需要做大量实验观察,很难一次性选准。
密度值:一般这个值都是偏小一些,然后进行多次尝试。
DBSCAN的可视化演示:Visualizing DBSCAN Clustering
评估方法:轮廓系数
- 计算样本 i 到同簇其它样本的平均距离 ai。ai越小,说明样本i越应该被聚类到该簇(将ai称为样本 i 到簇内不相似度)。
- 计算样本 i 到其它簇 Cj 的所有样本的平均距离 bij,称为样本 i 与簇 Cj 的不相似度。定义为样本 i 的簇间不相似度:bi=min(bi1,bi2,...,bik2)
- si接近1,则说明样本i聚类合理
- si接近-1,则说明样本i更应该分类到另外的簇
- 若si近似为0,则说明样本i在两个簇的边界上
Sklearn 中的密度聚类 DBSCAN:
参数:DBSCAN 的重要参数分为两类,一是DBSCAN 本身的参数,一类是最近邻度量参数。
1)eps: DBSCAN 算法参数,即ϵ-邻域的距离阈值,和样本距离超过ϵ-的样本点不在ϵ-邻域内。默认值是0.5。一般需要通过在多组值里面选择一个合适的阈值。eps过大会有更多的点会落在核心对象的ϵ-邻域,此时类别数可能会减少, 本来不是一类的样本也会被划为一类。反之则类别数可能会增大,本来是一类的样本却被划分开。
2)min_samples: DBSCAN算法参数,即样本点要成为核心对象所需要的ϵ-邻域的样本数阈值。默认值是5.。一般需要通过在多组值里面选择一个合适的阈值。通常和eps一起调参。在eps一定的情况下,min_samples过大,则核心对象会过少,此时簇内部分本来是一类的样本可能会被标为噪音点,类别数会变多。反之min_samples过小的话,则会产生大量的核心对象,导致类别过少。
3)metric:最近邻距离度量参数。可以使用的距离度量较多,一般来说DBSCAN使用默认的欧式距离(即p=2的闵可夫斯基距离)就可以满足我们的需求。可以使用的距离度量参数有:
在sklearn源码中找到的距离各种距离公式名称,补充如下
PAIRWISE_DISTANCE_FUNCTIONS = {
# If updating this dictionary, update the doc in both distance_metrics()
# and also in pairwise_distances()!
'cityblock': manhattan_distances,
'cosine': cosine_distances,
'euclidean': euclidean_distances,
'haversine': haversine_distances,
'l2': euclidean_distances,
'l1': manhattan_distances,
'manhattan': manhattan_distances,
'precomputed': None, # HACK: precomputed is always allowed, never called
'nan_euclidean': nan_euclidean_distances,
}
['braycurtis', 'canberra', 'chebyshev', 'correlation', 'cosine', 'dice', 'hamming',
'jaccard', 'kulsinski', 'mahalanobis', 'matching', 'minkowski', 'rogerstanimoto',
'russellrao', 'seuclidean', 'sokalmichener', 'sokalsneath', 'sqeuclidean', 'yule',
'wminkowski']
4)algorithm:最近邻搜索算法参数,auto
、ball_tree
(球树)、kd_tree
(kd树)、brute
(暴力搜索),默认是auto
。如果输入样本特征是稀疏的时候,sklearn 都会用蛮力实现。一般情况使用默认的 ‘auto’就够了。 如果数据量很大或者特征也很多,用"auto"建树时间可能会很长,效率不高,建议选择KD树实现‘kd_tree’,如果发现‘kd_tree’速度比较慢或者已经知道样本分布不是很均匀时,可以尝试用‘ball_tree’。
5)leaf_size:最近邻搜索算法参数,为使用KD树或者球树时, 停止建子树的叶子节点数量的阈值。这个值越小,则生成的KD树或者球树就越大,层数越深,建树时间越长,反之生成的KD树或者球树会小,层数较浅,建树时间较短。默认是30.。此值一般只影响算法运行速度和使用内存大小,一般情况下可以不管它。
6) p: 最近邻距离度量参数。只用于闵可夫斯基距离和带权重闵可夫斯基距离中p值的选择,
p=1为曼哈顿距离, p=2为欧式距离。如果使用默认的欧式距离不需要管这个参数。
DBSCAN
算法优缺点
优点:
- 不需要事先给定cluster的数目
- 可以发现任意形状的cluster
- 能够找出数据中的噪音,且对噪音不敏感
- 算法只需要两个输入参数
- 聚类结果几乎不依赖节点的遍历顺序
缺点:
-
DBSCAN
算法聚类效果依赖距离公式的选取,最常用的距离公式为欧几里得距离。但是对于高维数据,由于维数太多,距离的度量已变得不是那么重要,密度定义更加困难 -
DBSCAN
算法不适合数据集中密度差异很小的情况
密度聚类对于密度变化不大,且有重叠的数据的效果不好,两个簇有重叠很容易被聚类为同一个簇
设置合适的参数,可以很好的聚类环形嵌套的数据
属性值:
core_sample_indices_:核心对象数。
labels_:每个样本点的对应的类别,对于噪声点将赋值为-1。
import numpy as np
from collections import Counter
from sklearn.cluster import DBSCAN
model = DBSCAN(eps=0.1, min_samples=1, metric="cosine")
model.fit(X)
y_hat = model.labels_
unique_y_hat = np.unique(y_hat)
n_clusters = len(unique_y_hat) - (1 if -1 in y_hat else 0)
print("类别:", unique_y_hat, ";聚类簇数目:", n_clusters)
print(Counter(y_hat))
使用 cosine_similarity作为度量距离:
1. 使用余弦相似度作为距离度量标准预先计算距离矩阵,对距离矩阵预处理,使其符合定制的距离标准(可能类似于D = np.abs(np.abs(CD) -1),其中CD是余弦距离矩阵),metric为precomputed。
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.cluster import DBSCAN
total_samples = 1000
dimensionality = 3
points = np.random.rand(total_samples, dimensionality)
cosine_distance = cosine_similarity(points)
# option 1) vectors are close to each other if they are parallel
bespoke_distance = np.abs(np.abs(cosine_distance) -1)
# option 2) vectors are close to each other if they point in the same direction
bespoke_distance = np.abs(cosine_distance - 1)
results = DBSCAN(metric='precomputed', eps=0.25).fit(bespoke_distance)
2. 余弦距离= 1-余弦相似度;可能导致sklearn实现在O(n2)中运行。
3. 可以通过 -cosinesimilarity 作为预先计算的距离矩阵,使用-0.75作为eps。
4. 仅制作一个二进制距离矩阵(不过在O(n2)内存中是如此之慢),其中余弦相似度的距离= 0大于阈值,否则为0。然后使用eps = 0.5的DBSCAN。仅当相似度>阈值时,才能显示距离。
聚类的确不是分类,群集未标记。如果将其压缩到一种预测心态中(这不是最好的主意),实际上是在无需学习的情况下进行预测的。因为没有标记的训练数据可用于聚类。必须根据现有的内容为数据创建新的标签。但是不能在单个实例上执行此操作,只能"批量预测"。
但分配新点的功能很有用,如下一个快速实现:
import numpy as np
import scipy as sp
def dbscan_predict(dbscan_model, X_new, metric=sp.spatial.distance.cosine):
# Result is noise by default
y_new = np.ones(shape=len(X_new), dtype=int)*-1
# Iterate all input samples for a label
for j, x_new in enumerate(X_new):
# Find a core sample closer than EPS
for i, x_core in enumerate(dbscan_model.components_):
if metric(x_new, x_core) < dbscan_model.eps:
# Assign label of x_core to x_new
y_new[j] = dbscan_model.labels_[dbscan_model.core_sample_indices_[i]]
break
return y_new
def dbscan_predict(model, X): # 采用最接近样本的核心点
nr_samples = X.shape[0]
y_new = np.ones(shape=nr_samples, dtype=int) * -1
for i in range(nr_samples):
diff = model.components_ - X[i, :] # NumPy broadcasting
dist = np.linalg.norm(diff, axis=1) # Euclidean distance
shortest_dist_idx = np.argmin(dist)
if dist[shortest_dist_idx] < model.eps:
y_new[i] = model.labels_[model.core_sample_indices_[shortest_dist_idx]]
return y_new
也可尝试 sklearn HDBSCAN 中的approximate_predict对新点进行近似预测:
clusterer = hdbscan.HDBSCAN(min_cluster_size=15, prediction_data=True).fit(data)
test_labels, strengths = hdbscan.approximate_predict(clusterer, test_points)
谱聚类
基于谱图理论的一种聚类方法,具有在任意形状的样本空间上聚类并且收敛于全局最优解的优点。
- 通过对样本数据的 拉普拉斯矩阵的特征向量进行聚类,从而达到对样本数据进行聚类的目的;本质是将聚类问题转换为图的最优划分问题 ,是一种点对聚类算法。
- 谱聚类算法将数据集中的每个对象看做图的顶点V,将顶点间的相似度量化为相应顶点连接边E的权值w,这样就构成了一个基于相似度的无向加权图G(V,E),于是聚类问题就转换为图的划分问题。基于图的最优划分规则就是子图内的相似度最大,子图间的相似度最小。
谱聚类构建的主要步骤
- 构建表示对象相似度的矩阵W
- 构建度矩阵D(对角矩阵)
- 构建拉普拉斯矩阵L
- 计算矩阵L的前k个特征值的特征向量(k个列向量)
- 将k个列向量组成矩阵U
- 对矩阵U中的n行数据利用K-means或其它经典聚类算法进行聚类得出最终结果
应用场景
- 图形聚类、计算机视觉、非凸球形数据聚类等
问题
- 相似度矩阵的构建问题:业界一般使用高斯相似函数或者k近邻来作为相似度量,一般建议使用k近邻的方式来计算相似度权值
- 聚类数目的给定
- 如何选择特征向量
- 如何提高谱聚类的执行效率