K-Means 算法是无监督聚类算法,实现简单,聚类效果也不错,所以应用广泛。
1. K-Means 算法
K-Means 的思想非常简单:
- 对于给定的数据集,按照样本之间的距离,将数据集划分成 $K$ 个簇。
- 尽量让簇内的样本点尽可能的靠近,而簇间的样本则距离尽量疏远。
看到这个思想我们首先要搞清楚的问题是,如何衡量样本间的距离?K-Means 采用的是常见的欧式距离平方(Squared Euclidean Distance)作为样本之间的距离度量:
\[\begin{aligned} d(x_i, x_j) &= \sum _ {k=1} ^ n (x_{ki} - x_{kj})^2 \\ &=\| x_i - x_j\|^2 \end{aligned}\]其中 $n$ 为特征维度。基于此我们就可以考虑猜想的第二个部分,让簇内的样本尽可能的靠近,假设簇被划分为 $\left(C_{1}, C_{2}, \ldots C_{k}\right)$,我们通过衡量样本与其所属簇中心的距离总和作为损失函数,目标是最小化簇内距离:
\[E=\sum_{i=1}^{k} \sum_{x \in C_{i}}\left\|x-\mu_{i}\right\|_{2}^{2}\]其中 $\mu_i$ 是簇 $C_i$ 的均值向量,也被称为质心,表达式为:
\[\mu_{i}=\frac{1}{\left|C_{i}\right|} \sum_{x \in C_{i}} x\]然而,这是一个组合问题,$m$ 个样本分到 $k$ 个簇,那么可能的分法有:
\[S(m, k)=\frac{1}{k !} \sum_{l=1}^{k}(-1)^{k-l}\left(\begin{array}{c}{k} \\ {l}\end{array}\right) k^{m}\]这个明显是指数级别的问题,NP 难,现实中我们用启发式的迭代方式求解。
K-Means 启发式执行过程
图解如下:
- (a) 初始化数据集,假设 $k=2$;
- (b) 随机选择两个簇对应的质心;
- (c) 计算所有的样本离着这两个质心的距离,选择就近的质心归属该簇;
- (d) 对于两个簇的新样本,计算各自的样本均值,作为其新的质心;
- (e) 在新的质心下,重复 (c),得到新的两个簇;
- (f) 对于两个簇的新样本,重复 (d)。
在实际运行 K-Means 算法时,会多次重复步骤 (c)(d),才能达到较好的结果。
了解了 K-Means 的启发式流程后,可以发现几个要点:
- 对于 K-Means 算法,$K$ 的选取是非常重要的。
- 一般可以利用数据先验经验选择一个合适的 $K$ 值;
- 如果没有先验知识,可以通过交叉验证选择。
- $K$ 确定后,$K$ 个质心的初始化对结果和算法运行时间有较大影响。
- 需要选择合适的质心,最好这些质心不能相距太近。
1.1 K-Means 算法流程
传统的 K-Means 算法流程如下:
- 输入:样本集 $D=\{x_{1}, x_{2}, \ldots x_{m}\}$,聚类的簇数 $k$,最大迭代次数 $N$。
- 输出:划分 $C=\{C_{1}, C_{2}, \ldots C_{k}\}$
- 从样本集 $D$ 中随机选择 $k$ 个样本作为初始的 $k$ 个质心向量:$C=\{C_{1}, C_{2}, \ldots C_{k}\}$
- 对于 $n=1,2, \dots, N$
a)将簇划分 $C$ 初始化为 $C_{t}=\varnothing$ ($t=1,2 \ldots k$)
b) 对于 $\mathrm{i}=1,2 \ldots \mathrm{m}$,计算样本 $x_i$ 和各个质心向量 $\mu_j$ ($j=1,2, \ldots k$) 的距离 $d_{i j}=\vert\vert x_i-\mu_j\vert\vert_2^{2} $,将 $x_i$ 标记为最小的 $d_{ij}$ 所对应的类别 $\lambda_i$。此时更新 $C_{\lambda_i}=C_{\lambda_i} \cup\{x_{i}\}$。
c) 对于 $j=1,2, \dots, k$,对 $C_j$ 中所有的样本点重新计算新的质心 $\mu_{j}=\frac{1}{\vert\vert C_{j}\vert\vert } \sum_{x \in C_{j}} x$。
d) 如果所有的 $k$ 个质心向量都没有发生变化,则退出迭代,继续步骤 3。
- 输出簇划分 $C=\{C_{1}, C_{2}, \ldots C_{k}\}$。
2. K-Means 的优化
我们从 K-Means 的几个要点出发优化 K-Means,以期达到更好的使用效果。对于 K-Means 算法的调优可以从以下几个角度出发:
- 数据归一化和离群点处理
- 补充
- 选择合适的 $K$ 值
- 采用核函数
2.1 K-Means 初始化优化 $\rightarrow$ K-Means++
$K$ 个初始化的质心位置选择对后面的聚类结果和运行时间都有很大的影响,如果仅是完全采用随机的选择,有可能导致算法收敛很慢。K-Means++ 算法就是对 K-Means 随机初始化质心方法的优化。
K-Means++ 对初始化质心的优化策略也很简单:
- 从输入的数据集合中随机选择一个点作为第一个聚类中心 $\mu_1$;
- 对于数据集中的每一个点 $x_i$,计算其与已选择的聚类中心中距离最近的聚类中心距离:
- 选择一个新的数据点作为新的聚类中心,选择的原则是:$D(x)$ 较大的点,被选取到作为聚类中心的概率就越大。
- 重复步骤 2 和步骤 3 直到选择出 $k$ 个聚类质心。
- 利用这 $k$ 个质心来作为初始化质心去运行标准的 K-Means 算法。
2.2 K-Means $K$ 值确定优化 $\rightarrow$ ISODATA 算法
Blabla
2.3 K-Means 距离计算优化 $\rightarrow$ elkan K-Means
在传统的 K-Means 算法中,每一轮迭代,都需要计算所有样本点到所有质心的距离,这样计算量比较大较为耗时,elkan K-Means 算法就对此进行了优化,目标是减少不必要的距离计算,那么问题是哪些距离计算是不需要的呢?
elkan K-Means 利用了三角形的关系特性:两边之和大于第三边,两边之差小于等于第三边(可能共线,所以含等于),有如下两条规律:
- 对于一个样本点 $x$ 和两个质心 $\mu_{j_1}$,$\mu_{j_2}$,预先计算这两个质心之间的距离为 $D\left(j_{1}, j_{2}\right)$,如果发现 $2D\left(x, j_{1}\right) \leq D\left(j_{1}, j_{2}\right)$,那么我们就能推出 $2D\left(x, j_{1}\right) \leq D\left(j_{1}, j_{2}\right) \leq D\left(x, j_{1}\right) + D\left(x, j_{2}\right)$,于是立即能够得到 $D\left(x, j_{1}\right) \leq D\left(x, j_{2}\right)$,那么就省了一次计算距离。
- 对于一个样本点 $x$ 和两个质心 $\mu_{j_1}$,$\mu_{j_2}$,我们有 $D\left(x, j_{2}\right) \geq \max \{0, D\left(x, j_{1}\right)-D\left(j_{1}, j_{2}\right)\}$。
利用上述两个规律,elkan K-Means 比起传统的 K-Means 迭代速度上有很大的提高。有个问题是,如果样本的特征是稀疏的,有缺失值的话,此方法有些距离无法计算,不可用。
2.4 大样本优化 $\rightarrow$ Mini Batch K-Means
在大样本情况下,即使有 elkan K-Means 这样的优化,还是有大量计算存在,为此 Mini Batch K-Means 被提了出来。跟深度学习的 Mini Batch 一样,Mini Batch K-Means 也是采用一部分样本来进行做传统的 K-Means,这样避免大数据量的计算量难题,算法收敛速度大大加快。但此时有一个问题是,聚类的精确度就难以避免的有所降低,然而基本上能够接受。
在 Mini Batch K-Means 中,我们需要选择一个合适的 batch size,然后用 无放回的随机抽样出一个 mini batch 的样本集,在此基础上做 K-Means 聚类。为了增加算法的准确度,一般会做若干次 Mini Batch K-Means,并从中选择效果最好的。
3. 证明 $K$ 均值算法的收敛性
K-Means 总结
K-Means 优点:
- 原理比较简单,实现也是很容易,收敛速度快。计算复杂度是 $O(mKT)$ 接近线性,$m$ 是样本个数,$K$ 是簇个数,$T$是迭代轮数。
- 聚类效果较优。
- 算法的可解释度比较强。
- 主要需要调参的参数仅仅是簇数 $K$。
K-Means 缺点:
- $K$ 值的选取不好把握
- 易受初始值的影响
- 对于不是凸的数据集比较难收敛
- 如果各隐含类别的数据不平衡,比如各隐含类别的数据量严重失衡,或者各隐含类别的方差不同,则聚类效果不佳。(比如一类是另一类样本数量的 100 倍)
- 结果通常不是全局最优而是局部最优
- 不太适用于离散分类
- 样本点只能被划分到单一的类中
- 对噪音和异常点比较的敏感。