KMeans相关问题

爷,独闯天下 提交于 2019-12-15 14:42:50

K-means

k-means 聚类的原理

对于给定的样本集,按照样本之间的距离大小,将样本集划分成K个簇。让簇内的点尽量紧密的连在一起,而让簇间的距离尽量的大。
目标是最小化平方误差。定义样本与其所属类的中心之间的距离的总和最小
E=l=1KxCixμi2E = \sum_{l = 1}^K \sum_{x \in C_i} ||x - \mu_i||^2其中μi\mu_i是簇CiC_i的均值或者中心,有时也称质心,表达式为:μi=1CixCix\mu_i=\frac{1}{|C_i|}\sum_{x \in C_i}x

K-Means的优缺点及对应的改进

优点:
1) 原理比较简单,实现比较容易,收敛速度快
2) 聚类效果较优
3) 算法的可解释性比较强
4) 需要调的参数仅仅是簇数k
缺点:
1) K值的选取不好把握
2) 对于不是凸的数据集比较难收敛
3) 如果各类别的数据不平衡,比如各隐含类别的数据量严重失衡,或者各隐含类别的方差不同,则聚类效果不佳
4) 采用迭代方法,得到的结果只是局部最优值
5) 对噪声和异常点比较敏感

改进主要是针对K值的选择以及计算耗时上进行改进
K值的改进方法是使用K-Means++算法。因为k个初始化的质心的位置选择对最后的收敛结果和运行时间都会有很大的影响。

KMeans++的方法是
a)随机选择一个点作为聚类中心μ1\mu_1
b) 然后计算数据集中的每个点与已选聚类中心的距离D(x)=argminτ=1kselectedxiμτ22D(x)=argmin\sum_{\tau =1} k_{selected}||x_i - \mu_{\tau}||_2^2
c)添加一个新的数据点作为新的聚类中心,选择原则是D(x)较大的点被选择聚类中心的概率较大。
d) 重复b和c直至选择出k个聚类质心
e) 利用这k个质心来初始化质心去运行标准的kMeans算法

加快时间的优化主要有对距离计算的优化以及在大样本上使用小批量的数据进行KMeans去代替传统的KMeans方法
距离计算优化主要是减少不必要的距离的计算。利用的原理是三角形的两边之和大于第三边以及两边只差小于第三边来减少距离的计算。不过该方法如果样本的特征是稀疏的,有缺失值的话,此时某些距离无法计算,则不能使用该算法。
大样本优化Mini Batch K-Means:该方法是对样本集进行无放回采样,然后在采样出来的数据上做K-Means聚类。一般会多跑几次Mini Batch K-Means,得到不同的随机采样机来得到聚类簇,选择其中最优的聚类簇。

用 EM 算法推导解释 Kmeans

用EM算法解含有隐变量的最大似然问题就等价于用K-means算法解原聚类问题的解。
KMeans和EM算法在初始的时候都需要选择参数的初值。
EM算法的两步
: E步:固定模型参数的值,优化隐含数据的分布
: M步:固定隐含数据分布,优化模型参数的值
: 交替将极值推向最大

KMenas是两个步骤交替进行,可以分别看成是EM的E步和M步
E步中将每个点分给距离它最近的类,可以看做是EM算法中E步的近似
M步中将每个类的中心更新为分给该类各点的均值,可以认为是在各类分布均为单位方差的高斯分布的假设下的,最大似然值。(将类中心更新为类成员的中心值)

个人理解: KMeans初始的时候包含K个聚类中心,而这些聚类中心是不可见的,这个就相当于是EM中的隐变量,指定初值通过迭代法求解。

可参考: https://www.cnblogs.com/ljygoodgoodstudydaydayup/p/7274943.html
该网址中给出了数学的推导,有点复杂,下面给出部分
KMeans聚类问题:给定数据点x1,x2,,xNRmx_1, x_2, \cdot\cdot\cdot, x_N \in R^m,给定分类数目KK,求出KK个类中心μ1,μ2,,μKRm\mu_1, \mu_2, \cdot\cdot\cdot, \mu_K \in R^m,使得所有点到距离该点最近的类中心的距离的平方和i=1Nmin1kKxiμk22\sum_{i=1}^Nmin_{1 \leq k \leq K} ||x_i - \mu_k||_2^2最小。
**含隐变量的最大似然问题:**给定数据点x1,x2,,xNRmx_1, x_2, \cdot\cdot\cdot, x_N \in R^m,给定分类数目KK,考虑如下生成模型:
p(x,zμ1,μ2,,μK){exp(xμz22)xμz2=min1kKxμk20xμz2>min1kKxμk2 p\left(x, z | \mu_{1}, \mu_{2}, \ldots, \mu_{K}\right) \propto\left\{\begin{array}{ll}{\exp \left(-\left\|x-\mu_{z}\right\|_{2}^{2}\right)} & {\left\|x-\mu_{z}\right\|_{2}=\min _{1 \leq k \leq K}\left\|x-\mu_{k}\right\|_{2}} \\ {0} & {\left\|x-\mu_{z}\right\|_{2}>\min _{1 \leq k \leq K}\left\|x-\mu_{k}\right\|_{2}}\end{array}\right.
模型中的z{1,2,,K}z \in\{1,2, \ldots, K\}为隐变量,表示簇的类别
这个式子的直观意义:对于某个将要生成的点xx和类别号zz,如果xx属于类别zz,那么就以高斯分布的概率分布在这个类中心周围生成点xx,如果xx不属于类别zz,则不生成这个点
Q函数:完全数据的对数似然函数关于在给定观测数据Y和当前参数下对未观测数据Z的条件概率分布的期望称为Q函数
Q(θ,θ(i))=EZ[logP(Y,Zθ)Y,θ(i)]=ZlogP(Y,Zθ)P(ZY,θ(i))Q(\theta, \theta^{(i)}) = E_Z[logP(Y,Z|\theta)|Y,\theta^{(i)}]=\sum_ZlogP(Y,Z|\theta)P(Z|Y,\theta^{(i)})

KMeans的算法伪代码

算法流程:

  • (1)初始化,选择k个样本点作为初始聚类中心,(通常是随机选择)
  • (2)当样本进行聚类,计算每个样本到类中心的距离,将样本点分配到其最近的中心的类中
  • (3)计算新的类别中心,类中心为各个类中的样本的均值
  • (4)迭代收敛或者符合停止条件(通常类中心不再变化,即所有样本的分配结果不再发现变化)
  • (5)否则,返回步骤(2)继续迭代更新

伪代码:

创建k个点作为起始质心(经常是随机选择)
当任意一个点的簇分配结果发生改变时
    遍历样本集中的每个样本点
        遍历所有质心
            计算质心与数据点之间的距离
        将数据点分配到距离最近的簇
    对每个簇,计算簇中所有点的均值并将均值作为质心

KMeans算法的收敛

从之前关于KMeans的EM算法中可知,KMeans算法的收敛其实就相当于是EM算法的收敛证明。

EM算法的收敛性只要我们能够证明对数似然函数的值在迭代的过程中是增加的即可。
定理1: 设P(Yθ)P(Y|\theta)为观测数据的似然函数,θ(i)(i=1,2,)\theta^{(i)}(i = 1, 2, \cdots)为EM算法得到的参数估计序列,设P(Yθ(i))(i=1,2,)P(Y|\theta^{(i)})(i = 1, 2, \cdots)为对应的似然函数序列,则P(Yθ(i))P(Y|\theta^{(i)})是单调递增的,即P(Yθ(i+1))P(Yθ(i))P(Y|\theta^{(i+1)}) \geq P(Y|\theta^{(i)})

该定理证明可以查看《统计学习方法》P159页。 其实最重要的是使用了Jensen不等式。或者结合书本参考: https://blog.csdn.net/u010161630/article/details/52585764

定理2: 设L(θ)=P(Yθ)L(\theta) =P(Y|\theta)为观测数据的似然函数,θ(i)(i=1,2,)\theta^{(i)}(i = 1, 2, \cdots)为EM算法得到的参数估计序列,L(θ(i))(i=1,2,)L(\theta^{(i)})(i = 1, 2, \cdots)为对应的对数似然函数序列。
(1)如果P(Yθ)P(Y|\theta)有上界,则L(θ(i))=logP(Yθ(i))L(\theta^{(i)})=logP(Y|\theta^{(i)})收敛到某一个值LL^*
(2)在函数Q(θ,θ)Q(\theta, \theta^{\prime})L(θ)L(\theta)满足一定条件下,有EM算法得到的参数估计序列θ(i)\theta^{(i)}的收敛值θ\theta^*L(θ)L(\theta)的稳定点。

EM算法的收敛性包含关于对数似然函数序列L(θ(i))L(\theta^{(i)})L(θ)L(\theta)的收敛性和关于参数估计序列θ(i)\theta^{(i)}的收敛性两层意思,前者并不蕴含后者。此外定理只能保证参数估计序列收敛到对数似然函数序列的稳定点,不能保证收敛到极大值点。所以在应用中,初值的选择变得非常重要,常用的办法是选取几个不同的初值进行迭代,然后对得到的各个估计值加以比较,从中选择最好的。


简答版本: 定性描述一下KMeans的收敛性,首先定义畸变函数J(c,μ)=i=1mx(i)μc(i)J(c, \mu) = \sum_{i=1}^m ||x^{(i)} - \mu_{c^{(i)}}||
JJ函数表示每个样本点到其质心的距离平方和。KMeans算法的目的是要将JJ调整到最小。假设当前JJ没有达到最小值,那么首先可以固定每个类的质心μj\mu_j,调整每个样例的所属的类别c(i)c^{(i)}来让JJ函数减小,同样,固定c(i)c^{(i)}调整每个类的质心μj\mu_j,也可以使JJ减小,这两个过程就是内循环中使JJ单调递减的过程。当JJ递减到最小时,μ\mucc也同时收敛。
由于畸变函数J是非凸函数,意味着我们不能保证算法取得的最小值是全局最小值,也就是说k-means对质心初始位置的选取比较敏感。但一般情况下k-means达到的局部最优已经满足需求。但如果你怕陷入局部最优,那么可以选取不同的初始值跑多遍k-means,然后取其中最小的JJ对应的μ\mucc输出。

Kmeans 算法 K 怎么设置、适用什么样数据集

一般来说,会根据对数据的先验经验选择一个合适的k值,如果没有什么先验知识,则可以通过交叉验证选择一个合适的k值

怎么评价 Kmeans 聚类结果

EM算法

EM算法是一种迭代算法,用于含有隐变量的概率模型参数的极大似然估计,或极大后验概率估计。EM算法每次迭代由两步组成: E步,求期望; M步,求极大

一般地,用YY表示观测随机变量的数据,ZZ表示隐随机变量的数据。 YYZZ连在一起称为完全数据,观测数据YY又称为不完全数据。假设给定观测数据YY, 其概率分布是P(Yθ)P(Y|\theta) 其中θ\theta是需要估计的模型参数, 那么不完全数据YY的似然函数是P(Yθ)P(Y|\theta),对数似然函数L(θ)=logP(Yθ)L(\theta) = logP(Y|\theta),假设YYZZ的联合概率分布是P(Y,Zθ)P(Y,Z|\theta),那么完全数据的对数似然函数是log(Y,Zθ)log(Y,Z|\theta)EM算法通过迭代求L(θ)=logP(Yθ)L(\theta)=logP(Y|\theta)的极大似然估计。

EM算法:

  • 选择参数的初值θ(0)\theta^{(0)},开始迭代;
  • E步: 记θ(i)\theta^{(i)}为第ii次迭代参数θ\theta的估计值,在第i+1i+1次迭代的E步,计算Q(θ,θ(i))=Ez[logP(Y,Zθ)Y,θ(i)]=zlogP(Y,Zθ)P(ZY,θ(i))Q(\theta, \theta^{(i)}) = E_z[logP(Y,Z|\theta) | Y, \theta^{(i)}] = \sum_z logP(Y,Z|\theta)P(Z|Y,\theta^{(i)})
    这里,P(ZY,θ(i))P(Z|Y, \theta^{(i)})是给定观测值YY和当前的参数估计θ(i)\theta^{(i)}下隐变量数据ZZ的条件概率分布;
  • M步: 求使Q(θ,θ(i))Q(\theta, \theta^{(i)})极大化的θ\theta,确定第i+1i+1步迭代的参数的估计值θ(i+1)\theta^{(i+1)}
    θ(i+1)=argmaxθQ(θ,θ(i))\theta^{(i+1)} = \underset{\theta}{\operatorname{argmax}} Q(\theta, \theta^{(i)})
  • 重复第(2)步和第(3)步,直至收敛

其中EM的核心是Q(θ,θ(i))Q(\theta, \theta^{(i)}).
Q函数: 完全数据的对数似然函数logP(Y,Zθ)logP(Y,Z|\theta)关于在给定观测数据YY和当前参数θ(i)\theta^{(i)}下对未观测数据ZZ的条件概率分布P(ZY,θ(i))P(Z|Y, \theta^{(i)})的期望称为Q函数,即Q(θ,θ(i))=EZ[logP(Y,Zθ)Y,θ(i)]Q(\theta, \theta^{(i)}) = E_Z[logP(Y,Z|\theta) | Y, \theta^{(i)}]

几点说明:
步骤(1)参数的初值可以任意选择,但需注意EM算法对初值是敏感的。
步骤(2) E步求Q(θ,θ(i))Q(\theta, \theta^{(i)}).Q函数式中ZZ是未观测数据, YY是观测数据,注意,Q(θ,θ(i))Q(\theta, \theta^{(i)})的第1个变元表示要极大化的参数,第二个变元表示参数的当前估计值。每次迭代实际在求QQ函数及其极大。
步骤(3) M步求Q(θ,θ(i))Q(\theta, \theta^{(i)})的极大化,得到θ(i+1)\theta^{(i+1)},完成一次迭代θ(i)θ(i+1)\theta^{(i)} \rightarrow \theta^{(i+1)}后面将证明每次迭代使似然函数增大或达到局部极值。
步骤(4) 给定停止迭代的条件,一般是对较小的整数ϵ1,ϵ2\epsilon_1, \epsilon_2,若满足θ(i+1)θ(i)<ϵ1||\theta^{(i+1)}- \theta^{(i)}|| \lt \epsilon_1Q(θ(i+1),θ(i))Q(θ(i),θ(i))<ϵ2||Q(\theta^{(i+1)}, \theta^{(i)})- Q(\theta^{(i)}, \theta^{(i)})|| \lt \epsilon_2则停止迭代

tensorflow实现KMeans

参考:https://blog.csdn.net/m0_37885286/article/details/79410001

#代码思路:基本K-Means算法:
# 1、首先确定常数K,常数K意味着最终的聚类类别数;
# 2、随机选定初始点为质心,并通过计算每一个样本与质心之间的相似度(这里为欧式距离),将样本点归到最相似的类中;
# 3、接着,重新计算每个类的质心(即为类中心)
# 4、重复这样的过程,直到质心不再改变,最终就确定了每个样本所属的类别以及每个类的质心。

def kmeans_cluster(samples, k, generations):
    '''
    :param sample: 样本数
    :param k: 聚类中心数
    :param generations: 迭代次数
    '''
    sample_num = len(samples)
    dim = len(samples[0])

    data_points = tf.Variable(samples)
    cluster_labels = tf.Variable(tf.zeros([sample_num], dtype=tf.int64))
    
    # 声明并初始化每个分组所需要的几何中心
    rand_starts = np.array([samples[np.random.choice(sample_num)] for _ in range(k)])
    centroids = tf.Variable(rand_starts)
    
    # 计算每个点到每个几何中心的距离
    # 为了使用矩阵加快速度,将几何中心和数据点分别放到矩阵中,然后计算两个矩阵的欧几里得距离
    
    # centroid_matrix: 几何中心矩阵
    #tf.tile(centroids, [num_pts, 1])这行代码,表示,将矩阵中心复制150次,有3个矩阵中心,所以这里有450行,每一行有4个特征
    #tf.reshape(tf.tile(centroids, [num_pts, 1]), [num_pts, k, num_feats])表示将前面得到的 450 * 4的矩阵变为150*3*4的矩阵,表示分为150组,每组中有3个向量,每个向量里含有4个值
    centroid_matrix = tf.reshape(tf.tile(centroids, [sample_num, 1]), [sample_num, k, dim])
    
    # point_matrix 表示数据矩阵
    #tf.tile(data_points, [1,k])将data_points中的列复制3次,也就是原来是4列,现在变为12列,变为150*12
    #然后 reshape成 150*3*4,仍旧是150组,每组中有3个向量(这3个向量是相同的),每个向量有4个特征值
    point_matrix = tf.reshape(tf.tile(data_points, [1, k]), [sample_num, k, dim])
    
    # 于是对这2个矩阵计算其欧氏距离
    #reduction_indices = 2表示对于 a*b*c矩阵,把每个向量加起来成为一个新值,于是distance=150*3
    distances = tf.reduce_sum(tf.square(centroid_matrix - point_matrix), reduction_indices = 2)
    
    # 分配时,是以到每个数据点最小距离最接近的几何中心点
    
    centroid_group = tf.argmin(distances, 1)
    
    # 计算每组分类的平均距离得到新的几何中心
    def data_group_avg(group_ids, data):
	    # tf.unsorted_segment_sum按照group_ids中的序号进行分组求和,并放到对应的位置上
        sum_total = tf.unsorted_segment_sum(data, group_ids, k)
        num_total = tf.unsorted_segment_sum(tf.ones_like(data), group_ids, k)
        avg_by_group = sum_total / num_total
        return (avg_by_group)
    
    means = data_group_avg(centroid_group, data_points)
    # tf.assign 赋值操作
    update = tf.group(centroids.assign(means), cluster_labels.assign(centroid_group))
    
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        for i in range(generations):
            # print('Calculating gen {},out of {}.'.format(i, generations))
            _, centroid_group_count = sess.run([update, centroid_group])
            # group_count = []
            # for ix in range(k):
            #    group_count.append(np.sum(centroid_group_count==ix))
            # print('Group counts:{}'.format(group_count))
        [centers, assignments] = sess.run([centroids, cluster_labels])
    return centers, assignments
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!