文章目录
K-means
k-means 聚类的原理
对于给定的样本集,按照样本之间的距离大小,将样本集划分成K个簇。让簇内的点尽量紧密的连在一起,而让簇间的距离尽量的大。
目标是最小化平方误差。定义样本与其所属类的中心之间的距离的总和最小
E
=
∑
l
=
1
K
∑
x
∈
C
i
∣
∣
x
−
μ
i
∣
∣
2
E = \sum_{l = 1}^K \sum_{x \in C_i} ||x - \mu_i||^2
E=l=1∑Kx∈Ci∑∣∣x−μi∣∣2其中
μ
i
\mu_i
μi是簇
C
i
C_i
Ci的均值或者中心,有时也称质心,表达式为:
μ
i
=
1
∣
C
i
∣
∑
x
∈
C
i
x
\mu_i=\frac{1}{|C_i|}\sum_{x \in C_i}x
μi=∣Ci∣1∑x∈Cix
K-Means的优缺点及对应的改进
-
优点:
-
1) 原理比较简单,实现比较容易,收敛速度快
2) 聚类效果较优
3) 算法的可解释性比较强
4) 需要调的参数仅仅是簇数k
缺点:
-
1) K值的选取不好把握
2) 对于不是凸的数据集比较难收敛
3) 如果各类别的数据不平衡,比如各隐含类别的数据量严重失衡,或者各隐含类别的方差不同,则聚类效果不佳
4) 采用迭代方法,得到的结果只是局部最优值
5) 对噪声和异常点比较敏感
改进主要是针对K值的选择以及计算耗时上进行改进
K值的改进方法是使用K-Means++算法。因为k个初始化的质心的位置选择对最后的收敛结果和运行时间都会有很大的影响。
-
KMeans++的方法是
-
a)随机选择一个点作为聚类中心
μ
1
\mu_1
μ1
b) 然后计算数据集中的每个点与已选聚类中心的距离 D ( x ) = a r g m i n ∑ τ = 1 k s e l e c t e d ∣ ∣ x i − μ τ ∣ ∣ 2 2 D(x)=argmin\sum_{\tau =1} k_{selected}||x_i - \mu_{\tau}||_2^2 D(x)=argmin∑τ=1kselected∣∣xi−μτ∣∣22
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聚类问题:给定数据点
x
1
,
x
2
,
⋅
⋅
⋅
,
x
N
∈
R
m
x_1, x_2, \cdot\cdot\cdot, x_N \in R^m
x1,x2,⋅⋅⋅,xN∈Rm,给定分类数目
K
K
K,求出
K
K
K个类中心
μ
1
,
μ
2
,
⋅
⋅
⋅
,
μ
K
∈
R
m
\mu_1, \mu_2, \cdot\cdot\cdot, \mu_K \in R^m
μ1,μ2,⋅⋅⋅,μK∈Rm,使得所有点到距离该点最近的类中心的距离的平方和
∑
i
=
1
N
m
i
n
1
≤
k
≤
K
∣
∣
x
i
−
μ
k
∣
∣
2
2
\sum_{i=1}^Nmin_{1 \leq k \leq K} ||x_i - \mu_k||_2^2
∑i=1Nmin1≤k≤K∣∣xi−μk∣∣22最小。
**含隐变量的最大似然问题:**给定数据点
x
1
,
x
2
,
⋅
⋅
⋅
,
x
N
∈
R
m
x_1, x_2, \cdot\cdot\cdot, x_N \in R^m
x1,x2,⋅⋅⋅,xN∈Rm,给定分类数目
K
K
K,考虑如下生成模型:
p
(
x
,
z
∣
μ
1
,
μ
2
,
…
,
μ
K
)
∝
{
exp
(
−
∥
x
−
μ
z
∥
2
2
)
∥
x
−
μ
z
∥
2
=
min
1
≤
k
≤
K
∥
x
−
μ
k
∥
2
0
∥
x
−
μ
z
∥
2
>
min
1
≤
k
≤
K
∥
x
−
μ
k
∥
2
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.
p(x,z∣μ1,μ2,…,μK)∝{exp(−∥x−μz∥22)0∥x−μz∥2=min1≤k≤K∥x−μk∥2∥x−μz∥2>min1≤k≤K∥x−μk∥2
模型中的
z
∈
{
1
,
2
,
…
,
K
}
z \in\{1,2, \ldots, K\}
z∈{1,2,…,K}为隐变量,表示簇的类别
这个式子的直观意义:对于某个将要生成的点
x
x
x和类别号
z
z
z,如果
x
x
x属于类别
z
z
z,那么就以高斯分布的概率分布在这个类中心周围生成点
x
x
x,如果
x
x
x不属于类别
z
z
z,则不生成这个点
Q函数:完全数据的对数似然函数关于在给定观测数据Y和当前参数下对未观测数据Z的条件概率分布的期望称为Q函数
Q
(
θ
,
θ
(
i
)
)
=
E
Z
[
l
o
g
P
(
Y
,
Z
∣
θ
)
∣
Y
,
θ
(
i
)
]
=
∑
Z
l
o
g
P
(
Y
,
Z
∣
θ
)
P
(
Z
∣
Y
,
θ
(
i
)
)
Q(\theta, \theta^{(i)}) = E_Z[logP(Y,Z|\theta)|Y,\theta^{(i)}]=\sum_ZlogP(Y,Z|\theta)P(Z|Y,\theta^{(i)})
Q(θ,θ(i))=EZ[logP(Y,Z∣θ)∣Y,θ(i)]=Z∑logP(Y,Z∣θ)P(Z∣Y,θ(i))
KMeans的算法伪代码
算法流程:
- (1)初始化,选择k个样本点作为初始聚类中心,(通常是随机选择)
- (2)当样本进行聚类,计算每个样本到类中心的距离,将样本点分配到其最近的中心的类中
- (3)计算新的类别中心,类中心为各个类中的样本的均值
- (4)迭代收敛或者符合停止条件(通常类中心不再变化,即所有样本的分配结果不再发现变化)
- (5)否则,返回步骤(2)继续迭代更新
伪代码:
创建k个点作为起始质心(经常是随机选择)
当任意一个点的簇分配结果发生改变时
遍历样本集中的每个样本点
遍历所有质心
计算质心与数据点之间的距离
将数据点分配到距离最近的簇
对每个簇,计算簇中所有点的均值并将均值作为质心
KMeans算法的收敛
从之前关于KMeans的EM算法中可知,KMeans算法的收敛其实就相当于是EM算法的收敛证明。
EM算法的收敛性只要我们能够证明对数似然函数的值在迭代的过程中是增加的即可。
定理1: 设
P
(
Y
∣
θ
)
P(Y|\theta)
P(Y∣θ)为观测数据的似然函数,
θ
(
i
)
(
i
=
1
,
2
,
⋯
)
\theta^{(i)}(i = 1, 2, \cdots)
θ(i)(i=1,2,⋯)为EM算法得到的参数估计序列,设
P
(
Y
∣
θ
(
i
)
)
(
i
=
1
,
2
,
⋯
)
P(Y|\theta^{(i)})(i = 1, 2, \cdots)
P(Y∣θ(i))(i=1,2,⋯)为对应的似然函数序列,则
P
(
Y
∣
θ
(
i
)
)
P(Y|\theta^{(i)})
P(Y∣θ(i))是单调递增的,即
P
(
Y
∣
θ
(
i
+
1
)
)
≥
P
(
Y
∣
θ
(
i
)
)
P(Y|\theta^{(i+1)}) \geq P(Y|\theta^{(i)})
P(Y∣θ(i+1))≥P(Y∣θ(i))
该定理证明可以查看《统计学习方法》P159页。 其实最重要的是使用了Jensen不等式。或者结合书本参考: https://blog.csdn.net/u010161630/article/details/52585764
定理2: 设
L
(
θ
)
=
P
(
Y
∣
θ
)
L(\theta) =P(Y|\theta)
L(θ)=P(Y∣θ)为观测数据的似然函数,
θ
(
i
)
(
i
=
1
,
2
,
⋯
)
\theta^{(i)}(i = 1, 2, \cdots)
θ(i)(i=1,2,⋯)为EM算法得到的参数估计序列,
L
(
θ
(
i
)
)
(
i
=
1
,
2
,
⋯
)
L(\theta^{(i)})(i = 1, 2, \cdots)
L(θ(i))(i=1,2,⋯)为对应的对数似然函数序列。
(1)如果
P
(
Y
∣
θ
)
P(Y|\theta)
P(Y∣θ)有上界,则
L
(
θ
(
i
)
)
=
l
o
g
P
(
Y
∣
θ
(
i
)
)
L(\theta^{(i)})=logP(Y|\theta^{(i)})
L(θ(i))=logP(Y∣θ(i))收敛到某一个值
L
∗
L^*
L∗
(2)在函数
Q
(
θ
,
θ
′
)
Q(\theta, \theta^{\prime})
Q(θ,θ′)与
L
(
θ
)
L(\theta)
L(θ)满足一定条件下,有EM算法得到的参数估计序列
θ
(
i
)
\theta^{(i)}
θ(i)的收敛值
θ
∗
\theta^*
θ∗是
L
(
θ
)
L(\theta)
L(θ)的稳定点。
EM算法的收敛性包含关于对数似然函数序列 L ( θ ( i ) ) L(\theta^{(i)}) L(θ(i))与 L ( θ ) L(\theta) L(θ)的收敛性和关于参数估计序列 θ ( i ) \theta^{(i)} θ(i)的收敛性两层意思,前者并不蕴含后者。此外定理只能保证参数估计序列收敛到对数似然函数序列的稳定点,不能保证收敛到极大值点。所以在应用中,初值的选择变得非常重要,常用的办法是选取几个不同的初值进行迭代,然后对得到的各个估计值加以比较,从中选择最好的。
简答版本: 定性描述一下KMeans的收敛性,首先定义畸变函数
J
(
c
,
μ
)
=
∑
i
=
1
m
∣
∣
x
(
i
)
−
μ
c
(
i
)
∣
∣
J(c, \mu) = \sum_{i=1}^m ||x^{(i)} - \mu_{c^{(i)}}||
J(c,μ)=i=1∑m∣∣x(i)−μc(i)∣∣
J
J
J函数表示每个样本点到其质心的距离平方和。KMeans算法的目的是要将
J
J
J调整到最小。假设当前
J
J
J没有达到最小值,那么首先可以固定每个类的质心
μ
j
\mu_j
μj,调整每个样例的所属的类别
c
(
i
)
c^{(i)}
c(i)来让
J
J
J函数减小,同样,固定
c
(
i
)
c^{(i)}
c(i)调整每个类的质心
μ
j
\mu_j
μj,也可以使
J
J
J减小,这两个过程就是内循环中使
J
J
J单调递减的过程。当
J
J
J递减到最小时,
μ
\mu
μ和
c
c
c也同时收敛。
由于畸变函数J是非凸函数,意味着我们不能保证算法取得的最小值是全局最小值,也就是说k-means对质心初始位置的选取比较敏感。但一般情况下k-means达到的局部最优已经满足需求。但如果你怕陷入局部最优,那么可以选取不同的初始值跑多遍k-means,然后取其中最小的
J
J
J对应的
μ
\mu
μ和
c
c
c输出。
Kmeans 算法 K 怎么设置、适用什么样数据集
一般来说,会根据对数据的先验经验选择一个合适的k值,如果没有什么先验知识,则可以通过交叉验证选择一个合适的k值
怎么评价 Kmeans 聚类结果
EM算法
EM算法是一种迭代算法,用于含有隐变量的概率模型参数的极大似然估计,或极大后验概率估计。EM算法每次迭代由两步组成: E步,求期望; M步,求极大
一般地,用 Y Y Y表示观测随机变量的数据, Z Z Z表示隐随机变量的数据。 Y Y Y和 Z Z Z连在一起称为完全数据,观测数据 Y Y Y又称为不完全数据。假设给定观测数据 Y Y Y, 其概率分布是 P ( Y ∣ θ ) P(Y|\theta) P(Y∣θ), 其中 θ \theta θ是需要估计的模型参数, 那么不完全数据 Y Y Y的似然函数是 P ( Y ∣ θ ) P(Y|\theta) P(Y∣θ),对数似然函数 L ( θ ) = l o g P ( Y ∣ θ ) L(\theta) = logP(Y|\theta) L(θ)=logP(Y∣θ),假设 Y Y Y和 Z Z Z的联合概率分布是 P ( Y , Z ∣ θ ) P(Y,Z|\theta) P(Y,Z∣θ),那么完全数据的对数似然函数是 l o g ( Y , Z ∣ θ ) log(Y,Z|\theta) log(Y,Z∣θ)。 EM算法通过迭代求 L ( θ ) = l o g P ( Y ∣ θ ) L(\theta)=logP(Y|\theta) L(θ)=logP(Y∣θ)的极大似然估计。
EM算法:
- 选择参数的初值 θ ( 0 ) \theta^{(0)} θ(0),开始迭代;
- E步: 记 θ ( i ) \theta^{(i)} θ(i)为第 i i i次迭代参数 θ \theta θ的估计值,在第 i + 1 i+1 i+1次迭代的E步,计算 Q ( θ , θ ( i ) ) = E z [ l o g P ( Y , Z ∣ θ ) ∣ Y , θ ( i ) ] = ∑ z l o g P ( Y , Z ∣ θ ) P ( Z ∣ Y , θ ( 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)}) Q(θ,θ(i))=Ez[logP(Y,Z∣θ)∣Y,θ(i)]=z∑logP(Y,Z∣θ)P(Z∣Y,θ(i))
这里, P ( Z ∣ Y , θ ( i ) ) P(Z|Y, \theta^{(i)}) P(Z∣Y,θ(i))是给定观测值 Y Y Y和当前的参数估计 θ ( i ) \theta^{(i)} θ(i)下隐变量数据 Z Z Z的条件概率分布;- M步: 求使 Q ( θ , θ ( i ) ) Q(\theta, \theta^{(i)}) Q(θ,θ(i))极大化的 θ \theta θ,确定第 i + 1 i+1 i+1步迭代的参数的估计值 θ ( i + 1 ) \theta^{(i+1)} θ(i+1)
θ ( i + 1 ) = argmax θ Q ( θ , θ ( i ) ) \theta^{(i+1)} = \underset{\theta}{\operatorname{argmax}} Q(\theta, \theta^{(i)}) θ(i+1)=θargmaxQ(θ,θ(i))- 重复第(2)步和第(3)步,直至收敛
其中EM的核心是
Q
(
θ
,
θ
(
i
)
)
Q(\theta, \theta^{(i)})
Q(θ,θ(i)).
Q函数: 完全数据的对数似然函数
l
o
g
P
(
Y
,
Z
∣
θ
)
logP(Y,Z|\theta)
logP(Y,Z∣θ)关于在给定观测数据
Y
Y
Y和当前参数
θ
(
i
)
\theta^{(i)}
θ(i)下对未观测数据
Z
Z
Z的条件概率分布
P
(
Z
∣
Y
,
θ
(
i
)
)
P(Z|Y, \theta^{(i)})
P(Z∣Y,θ(i))的期望称为Q函数,即
Q
(
θ
,
θ
(
i
)
)
=
E
Z
[
l
o
g
P
(
Y
,
Z
∣
θ
)
∣
Y
,
θ
(
i
)
]
Q(\theta, \theta^{(i)}) = E_Z[logP(Y,Z|\theta) | Y, \theta^{(i)}]
Q(θ,θ(i))=EZ[logP(Y,Z∣θ)∣Y,θ(i)]
几点说明:
步骤(1)参数的初值可以任意选择,但需注意EM算法对初值是敏感的。
步骤(2) E步求
Q
(
θ
,
θ
(
i
)
)
Q(\theta, \theta^{(i)})
Q(θ,θ(i)).Q函数式中
Z
Z
Z是未观测数据,
Y
Y
Y是观测数据,注意,
Q
(
θ
,
θ
(
i
)
)
Q(\theta, \theta^{(i)})
Q(θ,θ(i))的第1个变元表示要极大化的参数,第二个变元表示参数的当前估计值。每次迭代实际在求
Q
Q
Q函数及其极大。
步骤(3) M步求
Q
(
θ
,
θ
(
i
)
)
Q(\theta, \theta^{(i)})
Q(θ,θ(i))的极大化,得到
θ
(
i
+
1
)
\theta^{(i+1)}
θ(i+1),完成一次迭代
θ
(
i
)
→
θ
(
i
+
1
)
\theta^{(i)} \rightarrow \theta^{(i+1)}
θ(i)→θ(i+1)后面将证明每次迭代使似然函数增大或达到局部极值。
步骤(4) 给定停止迭代的条件,一般是对较小的整数
ϵ
1
,
ϵ
2
\epsilon_1, \epsilon_2
ϵ1,ϵ2,若满足
∣
∣
θ
(
i
+
1
)
−
θ
(
i
)
∣
∣
<
ϵ
1
||\theta^{(i+1)}- \theta^{(i)}|| \lt \epsilon_1
∣∣θ(i+1)−θ(i)∣∣<ϵ1或
∣
∣
Q
(
θ
(
i
+
1
)
,
θ
(
i
)
)
−
Q
(
θ
(
i
)
,
θ
(
i
)
)
∣
∣
<
ϵ
2
||Q(\theta^{(i+1)}, \theta^{(i)})- Q(\theta^{(i)}, \theta^{(i)})|| \lt \epsilon_2
∣∣Q(θ(i+1),θ(i))−Q(θ(i),θ(i))∣∣<ϵ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