无监督学习: K-Means

学习地址

概念

  • 在监督学习中,我们所使用到的样本都是带有标签的,我们需要一个假设函数和决策线来进行分类,也就是说监督学习是有期望输出的,并且可以和实际值比较比较。
  • 在无监督学习中,样本不在具有标签,只是一堆散落的值而已。我们要做的是设计或者使用算法,并将这些无标签的数据输入到算法中,期望算法能够找出一些隐含在数据中的结构。如聚类算法,见下图
    2019-09-14 16-30-10 的屏幕截图.png

K-Means算法,最广泛运用的聚类算法

例子

2019-09-14 16-48-28 的屏幕截图.png
如何将上图样本分类两个簇(cluster),实际上簇的数量即K-Means中的K,后面会介绍如何选择K。

这里,我们先随机两个点X作为簇中心 , 遍历所有点计算离这两个点的距离并归类
2019-09-14 16-53-31 的屏幕截图.png

然后计算红色点簇的中心和蓝色点簇的中心,将之前的簇中心移动到新的中心位置。重复上述操作,直到簇中心不再改变。

K-Means算法输入

两个参数:K和X,K表示簇的数量,X为n维向量,不再需要x0=1
2019-09-14 17-01-33 的屏幕截图.png

算法过程

2019-09-14 17-09-15 的屏幕截图.png
两个循环分别表示例子中所述的两个步骤。
c(i)表示第i个样本所属的簇索引编号。uk表示簇中心。
可能会出线的一种情况,某个簇中心所在的集合为空,这样可以直接移除这个簇中心。

K-Means算法解决分离不佳的簇问题

衣服尺寸设计问题
2019-09-14 17-17-11 的屏幕截图.png

优化目标

最小化所有的样本点到其所属的簇中心距离之和
2019-09-15 10-44-01 的屏幕截图.png

随机初始化

K-Means算法第一步就是如何选取K个簇中心,避免局部最优。

  • 首先,不难理解聚类中心K的数量应该小于训练样本数量m,这里假设K给定
  • 随机选取K个训练样本作为簇中心μ1 … μk
  • 运行K-Means算法计算代价函数J
  • 重复上述操作100次或者10次,迭代次数根据训练样本数而定;找出代价函数最小的那次。
    2019-09-15 11-00-27 的屏幕截图.png

选取聚类数量

肘部法则: 改变K,计算最优代价函数,画图(代价函数关于K的变化),找到那个肘部即拐点,之后变化平缓了。
2019-09-15 11-14-48 的屏幕截图.png

但,大多数时候我们会得到右图的结果,这并不好决定。需要自己决定分类的目的是什么。


补充

sklearn中的聚类算法K-Means

聚类与分类

聚类 分类
核心 将数据分成多个组,探索每个组的数据是否有联系 从已经分组的数据中去学习,把新数据放到已经分好的组中去
学习类型 无监督,无需标签进行训练 有监督,需要标签进行训练
典型算法 K-Means,DBSCAN,层次聚类,光谱聚类 决策树,贝叶斯,逻辑回归
算法输出 聚类结果是不确定的,不一定总是能够反映数据的真实分类,同样的聚类,根据不同的业务需求可能是一个好结果,也可能是一个坏结果 分类结果是确定的,分类的优劣是客观的,不是根据业务或算法需求决定

sklearn中的聚类算法

聚类算法在sklearn中有两种表现形式,一种是类(和我们目前为止学过的分类算法以及数据预处理方法们都一样),需要实例化,训练并使用接口和属性来调用结果。另一种是函数(function),只需要输入特征矩阵和超参数,即可返回聚类的结果和各种指标。

含义
sklearn.cluster.Birch 实现Birtch聚类算法
sklearn.cluster.DBSCAN 从矢量数组或距离矩阵执行DBSCAN聚类
cluster.KMeans K均值聚类
cluster.MiniBatchKMeans 小批量K均值聚类
cluster.SpectralClustering 光谱聚类,将聚类应用于规范化拉普拉斯的投影
cluste.AgglomerativeClustering 凝聚聚类
函数 含义
cluster.k_means k均值聚类
cluster.ward_tree 光谱聚类
cluster.affinity_propagation 执行亲和传播数据聚类
cluster.mean_shift 使用平坦核函数的平均移位聚类

KMeans

KMeans

Kmeans没有损失函数

实例

  • sklearn.cluster.KMeans
    重要参数n_clusters:n_clusters是KMeans中的k,表示着我们告诉模型我们要分几类。这是KMeans当中唯一一个必填的参数,默认为8类。

数据:

1
2
3
4
5
6
7
8
9
10
11
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
X, y = make_blobs(n_samples=500,n_features=2,centers=4,random_state=1)
color = ["red","pink","orange","gray"]
for i in range(4):
plt.scatter(X[y==i, 0], X[y==i, 1]
,marker='o'
,s=8
,c=color[i]
)
plt.show()

数据
先简单实例化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from sklearn.cluster import KMeans
cluster = KMeans(n_clusters=3, random_state=0).fit(X) # 先设置3类,训练好模型

# 重要属性
y_pred = cluster.labels_ # 每个样本所对应的类,(500,)

pre = cluster.fit_predict(X) # 训练并预测所有数据所属类
print(pre==y_pred) # 全是True

centroid=cluster.cluster_centers_
print(centroid) # 簇心
'''
[[-7.09306648 -8.10994454]
[-1.54234022 4.43517599]
[-8.0862351 -3.5179868 ]]
'''

inertia=cluster.inertia_ # 总距离平方和
print(inertia) # 1903.4503741659223

查看结果:

1
2
3
4
5
6
7
8
9
color = ["red","pink","orange","gray"]
for i in range(3): # 聚类结果
plt.scatter(X[y_pred==i,0],X[y_pred==i,1]
,marker='o'
,s=8
,c=color[i])

plt.scatter(centroid[:,0],centroid[:,1],marker='X',s=15,c='black') # 绘制质心
plt.show()

聚类结果
根据整体平方和inertia和聚类结果可以发现橙色区域聚类效果可以更优,inertia可以更小。

尝试其他的n_clusters,可以发现簇数量越大,总距离平方和cluster.inertia_越小,但cluster.inertia_并不能用来评估算法好坏

聚类算法的模型评估指标

分类中,有直接结果(标签)的输出,并且分类的结果有正误之分,所以我们使用预测的准确度混淆矩阵ROC曲线等等指标来进行评估,但无论如何评估,都是在”模型找到正确答案“的能力。而回归中,由于要拟合数据,我们有SSE均方误差,有损失函数来衡量模型的拟合程度。但这些衡量指标都不能够使用于聚类。

面试高危问题:如何衡量聚类算法的效果?
聚类模型的结果不是某种标签输出,并且聚类的结果是不确定的,其优劣由业务需求或者算法需求来决定,并且没有永远的正确答案。那我们如何衡量聚类的效果呢?
KMeans的目标是确保簇内差异小,簇外差异大,可以通过衡量簇内差异来衡量聚类的效果。而Inertia是用距离来衡量簇内差异的指标,但是Inertia越小模型越好吗?

  • 首先,它不是有界的。我们只知道,Inertia是越小越好,是0最好,但我们不知道,一个较小的Inertia究竟有没有达到模型的极限,能否继续提高。
  • 第二,它的计算太容易受到特征数目的影响,数据维度很大的时候,Inertia的计算量会陷入维度诅咒之中,计算量会爆炸,不适合用来一次次评估模型。
  • 第三,Inertia对数据的分布有假设,它假设数据满足凸分布(即数据在二维平面图像上看起来是一个凸函数的样子),并且它假设数据是各向同性的(isotropic),即是说数据的属性在不同方向上代表着相同的含义。但是现实中的数据往往不是这样。所以使用Inertia作为评估指标,会让聚类算法在一些细长簇,环形簇,或者不规则形状的流形时表现不佳:
    环形簇
    可以看出,实际上期望效果应该是内环作为一簇,外环作为一簇,而如果使用cluster.inertia_作为衡量指标,效果就会很差
轮廓系数

最常用的聚类算法的评价指标。它是对每个样本来定义的,它能够同时衡量:

  1. 样本与其自身所在的簇中的其他样本的相似度a,等于样本与同一簇中所有其他点之间的平均距离
  2. 样本与其他簇中的样本的相似度b,等于样本与下一个最近的簇中得所有点之间的平均距离

根据聚类的要求”簇内差异小,簇外差异大“,我们希望b永远大于a,并且大得越多越好。
单个样本的轮廓系数计算为:
轮廓系数
即:
轮廓系数
很容易理解轮廓系数范围是(-1,1),其中值越接近1表示样本与自己所在的簇中的样本很相似,并且与其他簇中的样本不相似,当样本点与簇外的样本更相似的时候,轮廓系数就为负。当轮廓系数为0时,则代表两个簇中的样本相似度一致,两个簇本应该是一个簇。

在sklearn中,我们使用模块metrics中的类silhouette_score来计算轮廓系数,它返回的是一个数据集中,所有样本的轮廓系数的均值

  • 学习曲线
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    from sklearn.cluster import KMeans
    from sklearn.metrics import silhouette_score
    from sklearn.metrics import silhouette_samples

    score=[]
    for i in range(3,7):
    y_pred=KMeans(n_clusters=i,random_state=10).fit_predict(X)
    score.append(silhouette_score(X,y_pred))

    plt.plot(range(3,7),score)
    plt.xticks([3,4,5,6])
    plt.show()
    '''
    print(silhouette_samples(X,y_pred))
    这个是返回所有样本的聚类情况,为True或者False,如果是False则说明这个样本的轮廓系数为负,聚类失败
    '''

学习曲线