sklearn.cluster.KMeans(
n_clusters=8, *, init='k-means++', n_init='auto', max_iter=300, tol=0.0001, verbose=0, random_state=None,
copy_x=True, algorithm='lloyd')Clustering Algorithms
K-means 是一种简单的迭代性的聚类算法。对于数据集 \(D = \{x_1, x_2, ..., x_n\}\),其中 \(x_i \in \mathbb{R}^d\),需要指定利用 K-means 算法对数据划分成 \(k\) 个簇。对于数据集 \(D\) 的每个点 \(x_i\) 仅属于一个簇 \(S_i\),则 K-means 算法的目标函数可以表示为:
\[ \underset{S}{\operatorname{argmin}} \sum_{i=1}^{k} \sum_{x \in S_i} \|x - \mu_i\|_2^2 \]
其中 \(\mu_i\) 是簇 \(S_i\) 的均值向量。从目标函数不难看出,K-means 是通过一种“紧密程度”的形式对数据进行划分的,衡量这种“紧密程度”一般我们会用到“距离”的概念。距离可以理解为在集合 \(M\) 上的一个度量(Metric),即
\[ dist: M \times M \to \mathbb{R} \]
对于集合 \(M\) 中的 \(x, y, z\),下列条件均成立:
对于点 \(x = \left(x_1, x_2, ..., x_n\right)\) 和点 \(y = \left(y_1, y_2, ..., y_n\right)\),常用的距离为 \(p\) 阶明可夫斯基距离(Minkowski distance):
\[ dist\left(x, y\right) = \left(\sum_{i=1}^{n} |x_i - y_i|^p\right)^{\frac{1}{p}} \]
当 \(p = 1\) 时,称之为曼哈顿距离(Manhattan distance)或出租车距离:
\[ dist_{man}\left(x, y\right) = \sum_{i=1}^{n} |x_i - y_i| \]
当 \(p = 2\) 时,称之为欧式距离(Euclidean distance):
\[ dist_{ed}\left(x, y\right) = \sqrt{\sum_{i=1}^{n} \left(x_i - y_i\right)^2} \]
曼哈顿距离和欧式距离直观比较如图所示:
对于 K-means 算法,具体的计算过程如下:
通过上述步骤的计算,K-means 算法可以将样本点划分为 \(k\) 个簇,并得到每个簇的最终中心 \(\mu_i\)。
利用 K-means 算法,我们对 iris 数据集进行聚类分析。iris 数据集包含了 Sepal.Length,Sepal.Width,Petal.Length,Petal.Width 以及花的种类共 5 列数据。为了能够更直观的演示,我们仅采用 Petal.Length 和 Petal.Width 两列数据。K-means 是一种无监督的学习算法,因此我们并没有先验知识知道数据最适合分为几个簇,同时 K-means 算法又是一个对于聚类中心初始点敏感的算法,因此同样为了便于演示效果,在此我们设置簇的个数 \(k = 3\),\(3\) 个簇对应的初始中心点分别为 \(\mu_1 = \left(2, 1\right), \mu_2 = \left(4, 2\right), \mu_3 = \left(6, 1\right)\)。




第 1 轮,第 2 轮,第 3 轮和第 7 轮(最终轮)计算得出的结果。其中每幅图左上角 3 组坐标分别表示了 3 个簇的中心更新前和更新后的位置。图中的 ⦻ 号即为更新前簇的中心,箭头指向的方向即为更新后簇的中心,每轮计算中隶属不同簇的样本点利用颜色和形状加以了区分。
K-means 算法在一般数据集上可以的到较好的聚类效果,但同时也存在若干问题:
常用的参数如下表所示:
| 参数 | 描述 |
|---|---|
n_clusters |
聚类个数 |
init |
初始化方法,'k-means++', 'random' 或指定位置 |
n_init |
利用 centroid seeds 运行算法的次数 |
max_iter |
最大迭代次数 |
algorithm |
K-means 使用的算法,'full', 'elkan' |
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import load_iris
X, y = load_iris(return_X_y=True)
y_pred = KMeans(n_clusters=3).fit_predict(X[:, 2:])
plot_df = pd.DataFrame(
{'x': X[:, 2], 'y': X[:, 3], 'h': y_pred})
sns.scatterplot(
data=plot_df, x='x', y='y', s=100, hue='h',
palette=sns.color_palette('husl', 3))
层次聚类(hierarchical clustering)不同于 K-means 那种基于划分的聚类,通过对数据集在不同层次上进行划分,直至达到某种条件。层次聚类根据分层的方法不同,可以分为凝聚(agglomerative)层次聚类和分裂(divisive)层次聚类。
AGNES(Agglomerative Nesting)算法是一种凝聚层次聚类算法,其基本思想如下:

因此,对于 AGNES 算法而言,最关键的是如何计算两个簇之间的距离,对于簇 \(C_i\) 和簇 \(C_j\),常用的距离计算方法有:
\[ dist_{min} = \min \{dist\left(x, y\right) | x \in C_i, y \in C_j\} \]
\[ dist_{max} = \max \{dist\left(x, y\right) | x \in C_i, y \in C_j\} \]
\[ dist_{avg} = \dfrac{1}{|C_i| |C_j|} \sum_{x \in C_i} \sum_{y \in C_j} dist\left(x, y\right) \]
\[ dist_{med} = dist\left(Median_{C_i}, Median_{C_j}\right) \]
DIANA(Divisive Analysis)算法是一种分裂层次聚类算法,其基本思想如下:
在 DIANA 算法中,衡量一个簇 \(C\) 的大小,一般利用簇的直径,即簇中任意两个样本之间距离的最大值;衡量簇 \(C\) 中一个点 \(p\) 的平均相异度,一般利用该点到簇中其他点距离的平均值。
| 参数 | 描述 |
|---|---|
n_clusters |
聚类个数 |
affinity |
计算连接使用的度量,'euclidean', 'l1', 'l2', 'manhattan', 'cosine', 'precomputed' |
connectivity |
连接矩阵 |
compute_full_tree |
是否计算完整树 |
linkage |
连接准则,'ward', 'complete', 'average', 'single' |
distance_threshold |
距离阈值,大于该阈值则不合并 |
基于密度的聚类(density-based clustering)是一种通过样本的稠密程度划分聚类簇的方法。不同于基于距离的 K-means 和层次聚类方法往往只能生成球状的聚类簇,基于密度的聚类可以发现任意形状的聚类簇。
DBSCAN(density-based spatial clustering of applications with noise)是一种基于密度的聚类算法。DBSCAN 算法最重要的两个参数为 \(\epsilon\) 和 \(MinPts\),两个参数分别确定了领域半径和定义了核心点的阈值,通过这两个参数可以刻画样本分布的稠密程度。对于数据集 \(D = \{x_1, x_2, ..., x_n\}\),引入如下概念和记号:
\[ N_\epsilon \left(x\right) = \{y \in X | dist\left(x, y\right) \leq \epsilon\} \]
\[ \rho \left(x\right) = |N_\epsilon \left(x\right)| \]
核心点(core point)
对于 \(x \in D\),若 \(\rho \left(x\right) \geq MinPts\),则称 \(x\) 为一个核心点。假设 \(D\) 中所有核心点构成的集合为 \(D_{core}\),记 \(D_{n-core} = D \setminus D_{core}\) 为所有非核心点的集合。
边界点(border point)
对于 \(x \in D_{n-core}\),且 \(\exists y \in D\),满足 \[y \in N_\epsilon \left(x\right) \cap D_{core}\] 即点 \(x\) 所在的 \(\epsilon\) 邻域中存在核心点,则称 \(x\) 为 \(D\) 的边界点,记所有的边界点的集合为 \(D_{border}\)。
噪音点(noise point)
记 \(D_{noise} = D \setminus \left(D_{core} \cup D_{border}\right)\),对于 \(x \in D_{noise}\),则称 \(x\) 为噪音点。
核心点,边界点和噪音点示例如图所示:
其中 \(C\) 为 6 个核心点,\(B_1\) 和 \(B_2\) 为 2 个边界点,\(N\) 为 1 个噪音点。
密度直达(directly density-reachable)
对于 \(x, y \in D\),若 \(x \in D_{core}\),并且 \(y \in N_\epsilon \left(x\right)\),则称 \(y\) 由 \(x\) 密度直达。
密度可达(density-reachable)
若存在一个序列 \(p_1, p_2, ..., p_m \in D\),满足 \(p_{i+1}\) 由 \(p_i\) 密度直达,则称 \(p_m\) 由 \(p_1\) 密度可达。
密度相连(density-connected)
对于 \(x, y, z \in D\),若 \(y\) 和 \(z\) 均由 \(x\) 密度可达,则称 \(y\) 和 \(z\) 密度相连。
簇(cluster)
对于非空子集 \(C \in D\),如果称 \(C\) 为一个簇,则对于 \(x, y \in D\) 满足:
根据如上概念,DBSCAN 算法的基本为:从一个核心点 \(x\) 出发,寻找到 \(x\) 密度可达的所有样本点的集合 \(X = \{x' \in D | x' \ \text{由} \ x \ \text{密度可达}\}\),则 \(X\) 即为一个满足要求的簇。
DBSCAN 算法如下:
相比 K-means 算法,DBSCAN 算法有如下优势:
尽管相比 K-means,DBSCAN 算法有很多优势,但是对于不同的数据集,DBSCAN 算法的参数 \(\epsilon\) 和 \(MinPts\) 有时很难选取和优化。
一个非球形簇的数据分别利用 DBSCAN 算法和 K-means 算法进行聚类分析,对比结果如图所示:
| 参数 | 描述 |
|---|---|
eps |
用于确定邻域的最小距离 |
min_samples |
用于确定一个点是否为核心点的样本个数 |
metric |
距离度量,sklearn.metrics.pairwise_distances |
algorithm |
最近邻算法,'auto', 'ball_tree', 'kd_tree', 'brute' |
leaf_size |
用于 BallTree 或 cKDTree 的叶子个数 |
p |
用于计算 Minkowski 距离的 \(p\) 值 |
版权所有 © 范叶亮 Leo Van