机器学习之非监督学习(六)——聚类(K-Means)

K-means算法 (无监督算法,聚类算法)

1-1 基本流程


一、概念:


K-means中心思想:事先确定常数K,常数K意味着最终的聚类类别数,首先随机选定初始点为质心,并通过计算每一个样本与质心之间的相似度(这里为欧式距离),将样本点归到最相似的类中,接着,重新计算每个类的质心(即为类中心),重复这样的过程,直到质心不再改变,最终就确定了每个样本所属的类别以及每个类的质心。由于每次都要计算所有的样本与每一个质心之间的相似度,故在大规模的数据集上,K-Means算法的收敛速度比较慢。

聚类算法:是一种典型的无监督学习算法,主要用于将相似的样本自动归到一个类别中。
聚类算法与分类算法最大的区别是:聚类算法是无监督的学习算法,而分类算法属于监督的学习
算法,分类是知道结果的。
在聚类算法中根据样本之间的相似性,将样本划分到不同的类别中,对于不同的相似度计算方法,会得到不同的聚类结果,常用的相似度计算方法有欧式距离法。

二、主要特点:


常用距离
a.欧式距离
b.曼哈顿距离
应用:
a.去除孤立点,离群点,只针对度量算法,解决方法(常用归一化预处理方法 )
b.离散化

三、算法流程:


1.选择聚类的个数k(kmeans算法传递超参数的时候,只需设置最大的K值)
2.任意产生k个聚类,然后确定聚类中心,或者直接生成k个中心。
3.对每个点确定其聚类中心点。
4.再计算其聚类新中心。
5.重复以上步骤直到满足收敛要求。(通常就是确定的中心点不再改变。)

kmeans作用:去除奇异值
应为EM算法,kmeans肯定会稳定到K个中心点
kmeans算法k个随机初始值怎么选?
要多选几次,比较,找出最好的那个。
a.bi-kmeans方法,依次补刀
b.层次聚类 k = 5,找到5个中心点,接着把这个5个中心点喂给kmeans,初始中心点不同,收敛的结果也可能不一样的

四、小结


优点:
1、原理简单(靠近中心点) ,实现容易
2、聚类效果中上(依赖K的选择)
3、空间复杂度o(N)时间复杂度o(IKN)
N为样本点个数,K为中心点个数,I为迭代次数
缺点:
1、对离群点, 噪声敏感 (中心点易偏移)
2、很难发现大小差别很大的簇及进行增量计算
3、结果不一定是全局最优,只能保证局部最优(与K的个数及初值选取有关)

 

1-2 算法效果衡量标准


一、K值确定


Elbow method就是“肘”方法,对于n个点的数据集,迭代计算k from 1 to n,每次聚类完成后计算每个点到其所属的簇中心的距离的平方和,可以想象到这个平方和是会逐渐变小的,直到k==n时平方和为0,因为每个点都是它所在的簇中心本身。但是在这个平方和变化过程中,会出现一个拐点也即“肘”点,下图可以看到下降率突然变缓时即认为是最佳的k值。

è¿éåå¾çæè¿°

肘方法的核心指标是SSE(sum of the squared errors,误差平方和), Ci是第i个簇,
p是Ci中的样本点, mi是Ci的质心(Ci中所有样本的均值), SSE是所有样本的聚
类误差,代表了聚类效果的好坏。


 

肘方法的核心思想:
随着聚类数k的增大,样本划分会更加精细,每个簇的聚合程度会逐渐提高,那么误差平方和SSE自然会逐渐变小。并且,当k小于真实聚类数时,由于k的增大会大幅增加每个簇的聚合程度,故SSE的下降幅度会很大,而当k到达真实聚类数时,再增加k所得到的聚合程度回报会迅速变小,所以SSE的下降幅度会骤减,然后随着k值的继续增大而趋于平缓,也就是说SSE和k的关系图是一个手肘的形状,而这个肘部对应的k值就是数据的真实聚类数。这也是该方法被称为肘方法的原因。

聚类效果怎么判断?
1、SSE误差平方和越小越好,肘部拐点的地方。
2、也可用轮廓系数表示 系数越大,聚类效果越好,簇与簇之间距离越远

kmeans算法的最大弱点:只能处理球形的簇(理论)

代码实现:

import numpy as np
from sklearn.cluster import KMeans
from scipy.spatial.distance import cdist
import matplotlib.pyplot as plt
cluster1 = np.random.uniform(0.5, 1.5, (2, 10))
cluster2 = np.random.uniform(3.5, 4.5, (2, 10))

X = np.hstack((cluster1, cluster2)).T

'''
参数的意义:
n_clusters:簇的个数,即你想聚成几类
init: 初始簇中心的获取方法
n_init: 获取初始簇中心的更迭次数
max_iter: 最大迭代次数(因为kmeans算法的实现需要迭代)
tol: 容忍度,即kmeans运行准则收敛的条件
precompute_distances:是否需要提前计算距离
verbose: 冗长模式(不太懂是啥意思,反正一般不去改默认值)
random_state: 随机生成簇中心的状态条件。
copy_x: 对是否修改数据的一个标记,如果True,即复制了就不会修改数据。
n_jobs: 并行设置
algorithm: kmeans的实现算法,有:'auto', 'full', 'elkan', 其中 'full'表示用EM方式实现
'''
K = range(1, 10)
# print(X)
meandistortions = []
for k in K:
    kmeans = KMeans(n_clusters=k)
    kmeans.fit(X)
    meandistortions.append(sum(np.min(cdist(X,kmeans.cluster_centers_, 'euclidean'), axis=1)) / X.shape[0])
    '''
    # cdist(X, kmeans.cluster_centers_, 'euclidean')  求出X到cluster_centers_之间的距离
    #np.min(cdist(X,kmeans.cluster_centers_, 'euclidean'), axis=1)   按行的方向,对每一行求出一个最小值
    #sum(np.min(cdist(X,kmeans.cluster_centers_, 'euclidean'), axis=1)) 求出每次得到最小值列表的和
    # 求出每次最小值列表和的平均值
    '''
print(meandistortions)
plt.plot(K, meandistortions, 'bx-')
plt.xlabel('k')
# plt.ylabel('平均畸变程度',fontproperties=font)
plt.ylabel('Ave Distor')
# plt.title('用肘部法则来确定最佳的K值',fontproperties=font);
plt.title('Elbow method value K');
plt.show()


二、轮廓系数:


( Silhouette Coefficient)结合了聚类的凝聚度( Cohesion)和分离度
( Separation),用于评估聚类的效果。该值处于-1~1之间,值越大,表示聚类效果
越好。
 

a是Xi与同簇的其他样本的平均距离,称为凝聚度;
b是Xi与最近簇中所有样本的平均距离,称为分离度。

最近簇的定义:
 

其中p是某个簇中的样本。即,用Xi 到某个簇所有样本平均距离作为衡量该点到该簇的距离后,选择离Xi最近的一个簇作为最近簇。
求出所有样本的轮廓系数后再求平均值就得到了平均轮廓系数。平均轮廓系数的取值范围为[-1,1],且簇内样本的距离越近,簇间样本距离越远,平均轮廓系数越大,聚类效果越好。
代码实现:

import numpy as np
from sklearn.cluster import KMeans
from sklearn import metrics
import matplotlib.pyplot as plt

# 分割出6个子图, 并在1号作图
plt.figure(figsize=(8, 10))
plt.subplot(3, 2, 1)
# 初始化原始数字点
x1 = np.array([1, 2, 3, 1, 5, 6, 5, 5, 6, 7, 8, 9, 7, 9])
x2 = np.array([1, 3, 2, 2, 8, 6, 7, 6, 7, 1, 2, 1, 1, 3])
X = np.array(list(zip(x1, x2))).reshape(len(x1), 2)
# 在1号子图做出原始数据点阵的分布
# xlim 座标的刻度
plt.xlim([0, 10])
plt.ylim([0, 10])
plt.title('Sample')
plt.scatter(x1, x2)

# 点的颜色
colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b']
# 点的标号
markers = ['o', 's', 'D', 'v', '^', 'p', '*', '+']
# 簇的个数
tests = [2, 3, 4, 5, 8]
subplot_counter = 1  # 训练模型
for t in tests:
    subplot_counter += 1
    plt.subplot(3, 2, subplot_counter)
    kmeans_model = KMeans(n_clusters=t).fit(X)
    for i, l in enumerate(kmeans_model.labels_):
        plt.plot(x1[i], x2[i], color=colors[l], marker=markers[l], ls='None')
        plt.xlim([0, 10])
        plt.ylim([0, 10])
        # silhouette_score计算所有样本的平均轮廓系数。
        # kmeans_model.labels_ 每个样本的预测标签。即预测的类的标签
        # metric='euclidean' 用的方法为欧式距离
        plt.title('K = %s, SCoefficient = %.03f' % (t, metrics.silhouette_score(X, kmeans_model.labels_, metric='euclidean')))
plt.show()


三、Canopy算法配合初始聚类


1、Canopy简介:
Canopy聚类最大的特点是不需要事先指定k值(即clustering的个数),因此具有很大的实际应用价值。 Canopy聚类虽然精度较低,但其在速度上有很大优势,因此可以使用Canopy聚类先对数据进行“粗”聚类, 得到k值后再使用K-means进行进一步“细”聚类。

2、Canopy + Kmeans:
a. 聚类最耗费计算的地方是计算对象相似性的时候,Canopy聚类在第一阶段选择简单、计算代价较低的方法计算对象相似性,将相似的对象放在一个子集中,这个子集被叫做Canopy,通过系列计算得到若干Canopy,Canopy之间可以是重叠的,但不会存在某个对象不属于任何Canopy的情况, 可以把这一阶段看做数据预处理;
b . 在各个Canopy 内使用传统的聚类方法(如K-means),不属于同一Canopy的对象之间不进行相似性计算。 (即, 根据Canopy算法产生的Canopies代替初始的K个聚类中心点,由于已经将所有数据点进行Canopies有覆盖划分,在计算数据离哪个k-center最近时,不必计算其到所有k-centers的距离, 只计算和它在同一个Canopy下的k-centers这样可以提高效率)
c、Canopy详解:
1, 首先选择两个距离阈值: T1和T2, 其中T1 > T2
2, 从list中任取一点P,用低计算成本方法快速计算点P与所有Canopy之间的距离(如果当前不存在Canopy,则把点P作为一个Canopy),如果点P与某个Canopy距离在T1以内,则将点P加入到这个Canopy
3, 如果点P曾经与某个Canopy的距离在T2以内,则需要把点P从list中删除,这一步是认为点P此时与这个Canopy已经够近了, 因此它不可以再做其它Canopy的中心了
4, 重复步骤2、 3, 直到list为空结束

è¿éåå¾çæè¿°

优点:
1、 Kmeans对噪声抗干扰较弱,通过Canopy对比,将较小的NumPoint的Cluster直接去掉有利于抗干扰。
2、 Canopy选择出来的每个Canopy的centerPoint作为K会更精确。
3、 只是针对每个Canopy的内做Kmeans聚类, 减少相似计算的数量。
缺点:
算法中 T1、 T2(T2 < T1) 的确定问题

四、Calinski-Harabasz Index


Calinski-Harabasz:类别内部数据的协方差越小越好,类别之间的协方差越大越好,这样的Calinski-Harabasz分数s会高, 分数s高则聚类效果越好

 

其中m为训练集样本数, k为类别数。 为类别之间的协方差矩阵, 为类别内部数据的协方差矩阵。 tr为矩阵的迹。

1-3 算法优化


四种硬聚类算法(K-means++,二分K-means,ISODATA和Kernel K-means)

K-means++:


2007年由D. Arthur等人提出的K-means++针对图1中的第一步做了改进。可以直观地将这改进理解成这K个初始聚类中心相互之间应该分得越开越好。

那么初始点怎么选呢?
第一个簇心A随机找,是因为一开始你不知道哪个是簇心;
第二个簇心B要找距离A最远的,是因为簇心之间要相距远一些,如果很近的话,很容易当作一类,影响聚类效果;
第三个簇心C也是同样的,它得离A、B远一些;
其它依次类推。

怎么选取下一个聚类中心,整个算法的描述如下图所示:

 K-means++算法
 K-means++算法


                   

 

下面结合一个简单的例子说明K-means++是如何选取初始聚类中心的。数据集中共有8个样本,分布以及对应序号如下图所示:

è¿éåå¾çæè¿°
K-means++示例

 

假设经过图2的步骤一后6号点被选择为第一个初始聚类中心,那在进行步骤二时每个样本的D(x)和被选择为第二个聚类中心的概率如下表所示:

è¿éåå¾çæè¿°


其中的P(x)就是每个样本被选为下一个聚类中心的概率。最后一行的Sum是概率P(x)的累加和,用于轮盘法选择出第二个聚类中心。方法是随机产生出一个0~1之间的随机数,判断它属于哪个区间,那么该区间对应的序号就是被选择出来的第二个聚类中心了。例如1号点的区间为[0,0.2),2号点的区间为[0.2, 0.525)。
从上表可以直观的看到第二个初始聚类中心是1号,2号,3号,4号中的一个的概率为0.9。而这4个点正好是离第一个初始聚类中心6号点较远的四个点。这也验证了K-means的改进思想:即离当前已有聚类中心较远的点有更大的概率被选为下一个聚类中心。可以看到,该例的K值取2是比较合适的。当K值大于2时,每个样本会有多个距离,需要取最小的那个距离作为D(x)。

ISODATA


类别数目随着聚类过程而变化;
对类别数的“合并”: ( 当聚类结果某一类中样本数太少, 或两个类间的距离太近时)(样本太少或太散会被打散)
“分裂”( 当聚类结果中某一类的类内方差太大, 将该类进行分裂)

Kernel k-means


kernel k-means实际上公式上,就是将每个样本进行一个投射到高维空间的处理,然后再将处理后的数据使用普通的k-means算法思想进行聚类。

二分K-means


首先将所有点作为一个簇,然后将该簇一分为二。之后选择能最大限度降低聚类代价函数(也就是误差平方和)的簇划分为两个簇。 以此进行下去,直到簇的数目等于用户给定的数目k为止。

Mini Batch K-Means

对大数据分小批量处理
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章