K-Means 聚类算法

2025年3月17日 | 阅读 12 分钟

K-Means 聚类是一种无监督学习算法,用于解决机器学习或数据科学中的聚类问题。在本主题中,我们将学习什么是 K-means 聚类算法、算法的工作原理以及 K-means 聚类的 Python 实现。

什么是 K-Means 算法?

K-Means 聚类是一种无监督学习算法,它将未标记的数据集分成不同的簇。这里的 K 定义了在该过程中需要创建的预定义簇的数量,如果 K=2,则有两个簇,如果 K=3,则有三个簇,依此类推。

它是一种迭代算法,将未标记的数据集划分为 k 个不同的簇,使得每个数据集只属于具有相似属性的一个组。

它允许我们对数据进行分组,并以一种方便的方式自主发现未标记数据集中的类别组,而无需任何训练。

它是一种基于质心的算法,每个簇都与一个质心相关联。该算法的主要目标是最小化数据点与其对应簇之间的距离之和。

该算法以未标记的数据集为输入,将数据集划分为 k 个簇,并重复该过程,直到找不到最佳的簇。在此算法中,k 的值应预先确定。

K-means 聚类算法主要执行两项任务:

  • 通过迭代过程确定 K 个中心点或质心的最佳值。
  • 将每个数据点分配到离它最近的 k 个中心。靠近特定 k 个中心的数据点会形成一个簇。

因此,每个簇都有一些共同点,并且与其它簇是分开的。

下图解释了 K-means 聚类算法的工作原理

K-Means Clustering Algorithm

K-Means 算法如何工作?

K-Means 算法的工作原理通过以下步骤进行解释:

步骤 1:选择 K 值以确定簇的数量。

步骤 2:选择随机的 K 个点或质心。(它们可以是输入数据集中的点,也可以是其他点)。

步骤 3:将每个数据点分配到离它最近的质心,这将形成预定义的 K 个簇。

步骤 4:计算方差并放置每个簇的新质心。

步骤 5:重复第三步,即重新将每个数据点分配给每个簇的新近质心。

步骤 6:如果发生任何重新分配,则转到步骤 4,否则转到完成。

步骤 7:模型已准备就绪。

让我们通过考虑可视化图来理解上述步骤。

假设我们有两个变量 M1 和 M2。这两个变量的 x-y 轴散点图如下所示。

K-Means Clustering Algorithm
  • 我们取簇的数量 k,即 K=2,来识别数据集并将其放入不同的簇。这意味着我们将尝试将这些数据集分为两个不同的簇。
  • 我们需要选择一些随机的 k 个点或质心来形成簇。这些点可以是数据集中的点,也可以是其他任何点。因此,我们选择以下两个点作为 k 个点,它们不是我们数据集的一部分。请看下图。
    K-Means Clustering Algorithm
  • 现在,我们将每个散点图数据点分配到离它最近的 K 点或质心。我们将通过应用一些我们学过的数学来计算两点之间的距离来进行计算。因此,我们将在这两个质心之间画一条中线。请看下图。
    K-Means Clustering Algorithm

从上图可以看出,线左侧的点离 K1 或蓝色质心较近,线右侧的点离黄色质心较近。为了清晰可视化,我们将其涂成蓝色和黄色。

K-Means Clustering Algorithm
  • 由于我们需要找到最近的簇,我们将通过选择新质心来重复此过程。为了选择新质心,我们将计算这些质心的质心,并找到新的质心,如下所示。
    K-Means Clustering Algorithm
  • 接下来,我们将每个数据点重新分配给新的质心。为此,我们将重复找到中线的相同过程。中线将如下面的图像所示。
    K-Means Clustering Algorithm

从上图可以看出,有一点黄色在线的左侧,两点蓝色在线的右侧。因此,这三个点将被分配给新的质心。

K-Means Clustering Algorithm

由于发生了重新分配,我们将再次转到步骤 4,即查找新的质心或 K 点。

  • 我们将通过查找质心的质心来重复此过程,因此新的质心将如上图所示。
    K-Means Clustering Algorithm
  • 由于我们得到了新的质心,所以我们将再次画出中线并重新分配数据点。因此,图像将是:
    K-Means Clustering Algorithm
  • 我们可以看到上图,线上任一侧都没有不相似的数据点,这意味着我们的模型已经形成。请看下图。
    K-Means Clustering Algorithm

由于我们的模型已经准备好,现在我们可以移除假设的质心,最终的两个簇将如上图所示。

K-Means Clustering Algorithm

如何在 K-means 聚类中选择“K 个簇的数量”的值?

K-means 聚类算法的性能取决于它形成的有效簇。但是选择最佳簇数量是一项艰巨的任务。有几种不同的方法可以找到最佳簇数量,但在这里我们讨论最合适的方法来找到簇的数量或 K 的值。方法如下:

肘部法则

肘部法是寻找最佳簇数量最流行的方法之一。该方法使用 WCSS 值。WCSS 代表簇内平方和,它定义了簇内的总变化量。WCSS(对于 3 个簇)的计算公式如下:

WCSS= ∑Pi 在簇 1 中 距离(Pi C1)2 +∑Pi 在簇 2 中 距离(Pi C2)2+∑Pi 在簇 3 中 距离(Pi C3)2

在上面的 WCSS 公式中:

Pi 在簇 1 中 距离(Pi C1)2:这是簇 1 中每个数据点与其质心之间的距离平方和,其他两个项也相同。

要测量数据点和质心之间的距离,我们可以使用任何方法,例如欧几里得距离或曼哈顿距离。

为了找到最佳簇值,肘部法遵循以下步骤:

  • 它对给定的数据集执行 K-means 聚类,用于不同的 K 值(范围从 1-10)。
  • 对于每个 K 值,计算 WCSS 值。
  • 在计算出的 WCSS 值和簇数 K 之间绘制曲线。
  • 图的尖锐弯曲点看起来像一个肘部,那么该点就被认为是 K 的最佳值。

由于图显示了尖锐的弯曲,看起来像一个肘部,因此被称为肘部法。肘部法的图如下所示。

K-Means Clustering Algorithm

注意:我们可以选择簇的数量等于给定的数据点。如果我们选择的簇数量等于数据点的数量,那么 WCSS 的值将为零,这将是绘图的终点。

K-means 聚类算法的 Python 实现

在上面的部分,我们讨论了 K-means 算法,现在让我们看看如何使用Python来实现它。

在实现之前,让我们了解一下我们将在这里解决什么样的问题。所以,我们有一个Mall_Customers数据集,这是顾客在商场购物并消费的数据。

在给定的数据集中,我们有Customer_Id、Gender、Age、Annual Income ($) 和 Spending Score(这是计算出的顾客在商场消费的价值,值越高,消费越多)。从这个数据集中,我们需要计算一些模式,因为这是一种无监督方法,所以我们不知道确切要计算什么。

实现遵循的步骤如下:

  • 数据预处理
  • 使用肘部法找到最佳簇数量
  • 在训练数据集上训练 K-means 算法
  • 可视化簇

步骤 1:数据预处理步骤

第一步是数据预处理,正如我们在回归和分类的早期主题中所做的那样。但对于聚类问题,它将与其他模型不同。让我们讨论一下。

  • 导入库
    正如我们在之前的主题中所做的,首先,我们将导入我们模型的库,这是数据预处理的一部分。代码如下:

在上面的代码中,我们导入了numpy用于执行数学计算,matplotlib用于绘制图形,pandas用于管理数据集。

  • 导入数据集
    接下来,我们将导入我们需要使用的数据集。所以,这里我们使用的是 Mall_Customer_data.csv 数据集。可以使用以下代码导入:

通过执行以上几行代码,我们将在 Spyder IDE 中获得数据集。数据集如下所示。

K-Means Clustering Algorithm

从以上数据集中,我们需要从中找到一些模式。

  • 提取自变量

在这里,我们不需要任何因变量进行数据预处理步骤,因为这是一个聚类问题,我们对要确定的内容没有明确的想法。所以我们只为特征矩阵添加一行代码。

正如我们所见,我们只提取了第 3 个和第 4 个特征。这是因为我们需要一个 2D 图来可视化模型,并且一些特征是不需要的,例如 customer_id。

步骤 2:使用肘部法找到最佳簇数量

在第二步中,我们将尝试为我们的聚类问题找到最佳簇数量。所以,如上所述,这里我们将使用肘部法来完成此目的。

我们知道,肘部法使用 WCSS 概念通过在 Y 轴上绘制 WCSS 值并在 X 轴上绘制簇数量来绘制图。所以,我们将计算从 1 到 10 的不同 k 值的 WCSS 值。以下是代码:

如上代码所示,我们使用了 sklearn.cluster 库的KMeans类来形成簇。

接下来,我们创建了wcss_list变量来初始化一个空列表,该列表用于包含从 1 到 10 的不同 k 值计算出的 wcss 值。

之后,我们初始化了 for 循环,用于在从 1 到 10 的不同 k 值上进行迭代;由于 Python 中的 for 循环不包含边界值,因此取 11 以包含第 10 个值。

代码的其余部分与我们之前的主题相同,因为我们将模型拟合到特征矩阵上,然后绘制了簇数量和 WCSS 之间的图。

输出:执行上述代码后,我们将得到以下输出:

K-Means Clustering Algorithm

从上图可以看出,肘部点在5。所以这里的簇数量将是 5。

K-Means Clustering Algorithm

步骤 3:在训练数据集上训练 K-means 算法

由于我们已经得到了簇的数量,所以我们现在可以训练模型了。

要训练模型,我们将使用与上面部分相同的两行代码,但这里我们将使用 5 而不是 i,因为我们知道需要形成 5 个簇。代码如下:

第一行与上面创建 KMeans 类的对象相同。

在第二行代码中,我们创建了因变量y_predict来训练模型。

通过执行以上几行代码,我们将获得 y_predict 变量。我们可以在 Spyder IDE 中的变量浏览器选项下进行检查。我们现在可以将 y_predict 的值与我们的原始数据集进行比较。请看下图。

K-Means Clustering Algorithm

从上图可以看出,我们可以将 CustomerID 1 归类为属于簇

3(索引从 0 开始,因此 2 被视为 3),2 属于簇 4,依此类推。

步骤 4:可视化簇

最后一步是可视化簇。由于我们的模型有 5 个簇,我们将逐个可视化每个簇。

要可视化簇,我们将使用 matplotlib 的 mtp.scatter() 函数进行散点图绘制。

在上面的几行代码中,我们为从 1 到 5 的每个簇编写了代码。mtp.scatter 的第一个坐标,即 x[y_predict == 0, 0],包含用于显示特征矩阵值的 x 值,并且 y_predict 的范围从 0 到 1。

输出

K-Means Clustering Algorithm

输出图像清楚地显示了五个不同的簇,颜色不同。簇形成在数据集的两个参数之间;顾客的年收入和消费。我们可以根据需要或选择更改颜色和标签。我们还可以从上述模式中观察到一些点,如下所示:

  • 簇 1显示了平均薪水和平均消费的顾客,所以我们可以将这些顾客归类为
  • 簇 2 显示顾客收入高但消费低,所以我们可以将他们归类为谨慎
  • 簇 3 显示收入低且消费也低,所以他们可以被归类为明智。
  • 簇 4 显示收入低但消费非常高的顾客,所以他们可以被归类为不负责任
  • 簇 5 显示高收入和高消费的顾客,所以他们可以被归类为目标,这些顾客可能是商场老板最有利润的顾客。

K-Means 聚类算法选择题练习

1. 断言 (A): K-Means 聚类最小化了簇内的方差。

原因 (R): K-Means 聚类算法迭代地将数据点分配给最近的质心,并根据分配点的均值更新质心。

选项

  1. A 和 R 都为真,并且 R 是 A 的正确解释。
  2. A 和 R 都为真,但 R 不是 A 的正确解释。
  3. A 为真,但 R 为假。
  4. A 为假,但 R 为真。

答案

a) A 和 R 都为真,并且 R 是 A 的正确解释。

说明

K-Means 聚类旨在通过迭代地精炼簇质心并将点重新分配给最近的质心来最小化簇内的方差,从而确保每个簇中的点尽可能接近质心。


2. 使用 K-means++ 初始化方法的主要缺点是什么?

  1. 对于大型数据集,计算成本高昂
  2. 它总是导致相同的聚类结果
  3. 它需要手动调整簇的数量
  4. 它对球形簇效果不佳

答案

a) 对于大型数据集,计算成本高昂

说明

该过程需要计算所有点与选定质心之间的距离,从而增加了计算成本。


3. 在 K-means 算法的背景下,使用肘部法确定最佳簇数量有什么影响?

  1. 它总是能得到真正的簇数量
  2. 它可以帮助识别增加更多簇不会显著提高聚类质量的点
  3. 它确保簇均匀分布
  4. 它最大化了簇内的总变异

答案

b) 它可以帮助识别增加更多簇不会显著提高聚类质量的点

说明

肘部法识别出增加更多簇会带来收益递减的点。


4. 为什么 K-means 算法难以处理非线性可分数据?

  1. 它无法处理大型数据集
  2. 它假设簇是凸的
  3. 它需要归一化数据
  4. 它使用层次聚类

答案

b) 它假设簇是凸的

说明

K-means 假设簇是凸的和各向同性的,这不适合非线性簇形状。


5. K-means 算法如何解决确定簇数量 K 的问题?

  1. 通过使用基于数据大小的预定义启发式方法
  2. 通过迭代过程中的自动调整
  3. 通过依赖领域知识或肘部法等方法
  4. 通过始终将 K 设置为数据点数量的平方根

答案

c) 通过依赖领域知识或肘部法等方法

说明

K-means 依赖于用户指定的 K,通常基于领域知识或肘部法等方法。