优化目标
在机器学习这一领域中,很多算法都离不开一个损失函数。在深度学习中损失函数更是重要的一环。同样对于非监督学习的聚类算法K-Means来说,同样也需要一个 值来衡量它的聚类结果的好坏。
这个函数就是:
J
(
c
(
1
)
,
.
.
.
,
c
(
m
)
,
μ
1
,
.
.
.
,
μ
K
)
=
1
m
∑
i
=
1
m
∥
x
(
i
)
−
μ
c
(
i
)
∥
2
J(c^{(1)},...,c^{(m)},\mu_1,...,\mu_K) = \frac{1}{m}\sum_{i=1}^{m}\|x^{(i)} - \mu_{c^{(i)}}\|^2
J(c(1),...,c(m),μ1,...,μK)=m1i=1∑m∥x(i)−μc(i)∥2
这里的 c ( i ) c^{(i)} c(i) 表示第 i 个样本属于哪一个聚类中心。 μ i \mu_i μi 表示第几个聚类中心。 x i x^i xi 表示第i个样本点。而我们的目的,就是最小化这个目标函数。即: m i n i m i z e c ( 1 ) , . . . , c ( m ) , μ 1 , . . . , μ K J ( c ( 1 ) , . . . , c ( m ) , μ 1 , . . . , μ K ) minimize_{c^{(1)},...,c^{(m)},\mu_1,...,\mu_K}{J(c^{(1)},...,c^{(m)},\mu_1,...,\mu_K) } minimizec(1),...,c(m),μ1,...,μKJ(c(1),...,c(m),μ1,...,μK)
对于上面的目标函数,其实就是在计算 每个类中 的样本点距离类中心点的距离。当然一般来说中心点都会选择类内样本点的中心点,可以简单的理解为上面的目标函数最终目的就是在最小化类内方差。
因为方差的公式正好就是 D X = E ( X − E ( X ) ) 2 DX = E(X-E(X))^2 DX=E(X−E(X))2
也就是说它在试图让每一个分类结果的样本点尽可能集中在一起。
K-Means算法过程
为了更好理解K-Means算法是怎么优化优化目标的,有必要把K-Means算法的步骤简单回顾一下。
- 根据要分类的数量 K 随机初始化 K 个聚类中心点,即 μ 1 , μ 2 , . . . , μ k \mu_1, \mu_2,...,\mu_k μ1,μ2,...,μk。当然因为是随机初始化的所以这些点基本不可能就是最好的聚类中心点。
- 计算每一个样本点 x i x_i xi 到这 K 个聚类中心点 μ 1 , . . . , μ K \mu_1, ..., \mu_K μ1,...,μK 的距离,选择距离最近的聚类中心点例如最近的点为 μ j \mu_j μj,就将 x i x_i xi 归类为这一类。即为 c ( i ) = j c^{(i)} = j c(i)=j。
- 在上面的步骤中,每一个点都已经分好类了,这个时候,重新计算分好类的每一个类的样本点的中心点,因为对于这些聚类中心点通常不会是这些样本点的中心点,它们只是相比较于其他的样本中心点距离本类的样本点的距离最近而已。将聚类中心点更新为新计算到的中心点。即: μ j : = m e a n ( { x i ∣ c ( i ) = j } ) \mu_j := mean(\{x_i|c^{(i)} =j\}) μj:=mean({xi∣c(i)=j})
- 重复步骤 2,3, 直至聚类中心点收敛,即 μ 1 , . . . , μ K \mu_1, ...,\mu_K μ1,...,μK 不再变化。
算法解释
我们知道了目标函数其实是在最小化聚类结果的类间的样本点到聚类中心的距离。最终结果其实是得到一个最小的类内方差。
我们先将优化目标公式再写一遍:
J
(
c
(
1
)
,
.
.
.
,
c
(
m
)
,
μ
1
,
.
.
.
,
μ
K
)
=
1
m
∑
i
=
1
m
∥
x
(
i
)
−
μ
c
(
i
)
∥
2
J(c^{(1)},...,c^{(m)},\mu_1,...,\mu_K) = \frac{1}{m}\sum_{i=1}^{m}\|x^{(i)} - \mu_{c^{(i)}}\|^2
J(c(1),...,c(m),μ1,...,μK)=m1i=1∑m∥x(i)−μc(i)∥2
-
首先我们来看算法的第 2 个步骤。
它挑选了对于当前的聚类中心点最近的样本点作为分类的结果,这个步骤的目的就是找到一个对于当前的聚类中心点集合目标公式值最小的分类方式。 也就是说对于当前聚类中心点来说,这种分类方式是能让 目标函数值最小的分类方式。 其他任何一种分类方式得到的 J J J 都会比这种分类方式要大。
其实靠想象就知道,那个近就分给那个,这样的到的平均距离肯定是最小的。
-
然后再来看看算法的第 3 个步骤。
首先我们知道,虽然第 2 个步骤已经把每一个样本都进行了归类,但是,是没有办法保证这个聚类中心点就是最优的聚类中心点,因为很显然,它的优化的目标公式还有下降的空间。从算法的第 3 个步骤的解释中我们知道,当前的聚类结果的聚类中心点可能不是聚类结果的中心点。
随机变量的方差有一个性质即:对于任意的实数C,都有 E ( X − C ) 2 ≥ E ( X − E ( X ) ) 2 = D ( X ) E(X-C)^2 \ge E(X-E(X))^2=D(X) E(X−C)2≥E(X−E(X))2=D(X), 也就是说,随机变量X和它期望(中心点)的距离平均值(偏差程度)比到其他任何点的距离的平均值都小。
也就是说,对于在第 2 个步骤中得到的聚类结果,当前的聚类中心点移动到聚类结果的中心点的位置可以得到更小的目标函数值。所以就有了更新聚类中心点到聚类后结果的中心点这一步。
因为更新了聚类中心点后,对于这个新的聚类中心点,当前的聚类结果就不一定是最优的聚类结果了,因为聚类中心点位置变了,所以每个样本到聚类中心点的位置也变了。所以要重复步骤2和步骤3直到目标函数 J 收敛,这个时候我们就得到了一个较好的结果。
算法总结
总的来说,算法的在做这样的事情。
- 根据当前聚类中心点进行聚类 → \rightarrow → 得到使得当前聚类中心点最小的目标函数值得的类结果。
- 根据聚类结果更新聚类中心点 → \rightarrow → 得到使得新的到的聚类结果最小的目标函数值的聚类中心点
- 重复上面的步骤
可以看得到,在每一个步骤中,目标函数都在朝着不增的方向变化,直到我们得到一个收敛的比较小的值。这一点其实和梯度下降的作用有那么一点的相似,都是在迭代过程中不断更新参数使得目标函数最小化,从而得到一个局部最优值或者全局最优值(当然,这是我们期望的)。
扩展
其实对于K-Means算法的目标函数来说,只是最小化了聚类结果内部的距离。这样不一定能的到最好的聚类结果,也就是最终的优化结果可能是一个局部最优。这个和初始的聚类中心点的位置是有关的。
比如:对于同一个数据集合,由于初始化的不同,最终的聚类结果也可能不同:
因此。按照正常的需求的话,我们真正的期望应该要达到:类内方差最小化,类间方差最大化。
这里的解决方法有两种:
- 一个就是吴恩达在机器学习课程中提到的那样,多次进行聚类,然后选择聚类结果好的模型,其实就是选择一个目标函数J值最小的模型。
在python中,就是将设置KMeans算法的n_init 参数。例如
这里的n_init=10,就是运行10次Kmean算法,然后挑选最优的一个。from sklearn.cluster import KMeans km = KMeans(n_clusters=3, init="random", n_init=10, max_iter=300, tol=1e-4, random_state=0)
- 另一个就是使用KMeans++算法,KMeans++ 算法的一个思想就是在初始化聚类中心点的时候不是随机化,而是选择尽可能远的中心点,这样也就尽最大可能让类间距离变大。
使用KMeans++我们只需要把上面的参数 init 换成 “k-means++" 即可。