本文将从零拆解无监督学习两大经典聚类算法 K-means 与 DBSCAN 的核心原理、评价指标,基于啤酒数据集完成全流程 Python 代码实战,对比两种算法的优劣与适用场景,零基础也能轻松上手复现

        在无监督学习领域,聚类算法是挖掘数据内在分布规律的核心工具。其中K-means作为划分式聚类的代表,以简单高效的特性成为入门首选;而DBSCAN作为密度式聚类的经典算法,完美解决了 K-means 无法处理非球形簇、对噪声敏感的痛点。本文将基于啤酒特征数据集,从算法原理、代码实现、效果评估、场景对比四个维度,完成两大算法的全链路讲解。

关键词:无监督学习;K-means;DBSCAN;聚类算法;Python;机器学习

一、聚类算法与无监督学习概述

        无监督学习的核心特点是训练数据无人工标注的标签,算法需要自主挖掘数据的内在结构与分布规律。而聚类是无监督学习最核心的应用场景之一,其目标是:将相似的样本划分到同一个簇(Cluster)中,同时保证不同簇之间的样本差异最大化。

本文将重点讲解两大经典聚类算法:

        K-means:划分式聚类的标杆,简单高效,适合常规球形分布数据集

        DBSCAN:密度式聚类的代表,支持任意形状簇,可自动识别噪声数据

二、K-means 算法核心原理详解

2.1 基本概念与核心思想

        K-means 的核心逻辑是通过迭代优化,将数据集划分为 K 个预先指定的、互不重叠的簇,每个簇由其质心(簇内所有样本的均值)代表。

其核心基础概念如下:

        1.簇数量 K:需要预先指定聚类的最终簇数,这是 K-means 最核心的输入参数

        2.距离度量:用于衡量样本间的相似度,最常用的是欧氏距离,也可使用曼哈顿距离

                 欧氏距离公式:d=\sqrt{(x_{1}-x_{2})^{2}+(y_{1}-y_{2})^{2}}

                曼哈顿距离公式:d=|x_{1}-x_{2}|+|y_{1}-y_{2}|

        3.质心:每个簇内所有样本向量的均值,作为该簇的核心代表​

        4.优化目标:最小化每个样本到其所属簇质心的平方误差和,公式为:min \sum_{i=1}^{K} \sum_{x \in c_{i}}(c_{i}, x)^{2}其中c_i为第 i 个簇的质心,​x为簇内的样本。

2.2 算法执行步骤

        K-means 的执行流程清晰可复现,核心分为 4 步:

  1. 随机从数据集中选取 K 个样本,作为初始的簇质心
  2. 计算每个样本到所有质心的距离,将样本分配到距离最近的质心所属的簇
  3. 对每个簇,重新计算其所有样本的均值,得到更新后的质心
  4. 重复步骤 2-3,直到质心不再发生变化,或达到预设的最大迭代次数

2.3 聚类效果评价:轮廓系数

        K-means 的聚类效果无法用分类任务的准确率等指标评估,最常用的评价指标是轮廓系数(Silhouette Coefficient),它同时兼顾了簇内的凝聚度和簇间的分离度。

轮廓系数核心公式:S(i)=\frac{b(i)-a(i)}{max \{a(i), b(i)\}}

        a(i):第 i 个样本与其同簇内所有其他样本距离的平均值,代表簇内凝聚度,值越小说明簇内相似度越高        

        b(i):第 i 个样本与其他所有簇的平均距离的最小值,代表簇间分离度,值越大说明簇间区分度越好

轮廓系数取值含义

        轮廓系数的取值范围为[−1,1],不同取值对应不同的聚类效果:

        接近 1:样本聚类合理,簇内凝聚度高、簇间分离度好

        接近 - 1:样本聚类不合理,该样本更应该被划分到其他簇

        接近 0:样本处于两个簇的边界上,聚类效果模糊

        在实际应用中,我们可以遍历不同的 K 值,计算对应聚类结果的平均轮廓系数,选择轮廓系数最大的 K 作为最优簇数。

2.4 K-means 优缺点

优点
  • 算法原理简单,收敛速度快,计算效率高,适合常规的大规模数据集
  • 聚类结果可解释性强,每个簇的核心特征可通过质心直观体现
缺点
  • 必须预先指定 K 值,而在实际业务场景中,K 值往往难以提前确定
  • 对初始质心的选择敏感,不同的初始值可能得到完全不同的聚类结果
  • 仅能发现球形分布的簇,对任意形状的簇(如环形、带状)聚类效果极差
  • 对异常值和噪声非常敏感,异常值会严重干扰质心的计算,导致聚类结果偏移

三、K-means 算法 Python 实战(啤酒数据集)

3.1 数据集介绍

        本文使用的是 20 款啤酒的特征数据集,共包含 5 个字段,数据内容如下:

字段说明:name:啤酒名称,calories:卡路里含量,sodium:钠含量,alcohol:酒精度,cost:价格

3.2 环境准备

        首先安装所需的 Python 依赖库:

pip install pandas scikit-learn matplotlib

3.3 完整代码实现

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn import metrics

plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC", "sans-serif"]
plt.rcParams["axes.unicode_minus"] = False 

# 读取数据集,分隔符为空格
beer = pd.read_table("data.txt", sep=" ", encoding="utf8")
# 查看数据集前5行
print("数据集预览:")
print(beer.head())
# 查看数据集基本信息
print("\n数据集基本信息:")
print(beer.info())

X = beer[["calories", "sodium", "alcohol", "cost"]]
# 遍历K值范围
k_range = range(2, 10)
scores = []

for k in k_range:
    # 初始化KMeans模型,设置随机种子保证结果可复现
    kmeans = KMeans(n_clusters=k, random_state=0, n_init=10)
    # 训练模型并获取聚类标签
    labels = kmeans.fit(X).labels_
    # 计算轮廓系数
    score = metrics.silhouette_score(X, labels)
    scores.append(score)
    print(f"K={k} 时,轮廓系数为: {score:.4f}")

# 绘制轮廓系数随K值变化的曲线
plt.figure(figsize=(10, 6))
plt.plot(k_range, scores, marker='o', linewidth=2, color='#1f77b4')
plt.xlabel("Number of Clusters Initialized", fontsize=12)
plt.ylabel("Silhouette Score", fontsize=12)
plt.title("轮廓系数随K值变化曲线", fontsize=14)
plt.grid(True, alpha=0.3)
plt.show()

3.5 聚类结果解读

从输出结果可以看到,20 款啤酒被清晰划分为 2 个簇:

1. 轮廓系数曲线核心结论

        运行结果中,K=2 时轮廓系数达到全局最大值 0.6918,是 K=2~9 区间的最高值,明确说明K=2 是当前啤酒数据集的最优聚类簇数

2. 数值变化的专业解读

1.整体趋势:从 K=2 到 K=9,轮廓系数呈持续下降趋势,说明随着簇数增加,聚类的「簇内凝聚度 + 簇间分离度」持续变差,强行拆分簇会导致聚类合理性大幅降低。

2.分段特征:

        K=2→K=3,轮廓系数仅小幅下降(0.6918→0.6732),说明 K=3 也具备不错的聚类效果,但稳定性和区分度不如 K=2;

        K=4 之后轮廓系数出现断崖式下跌,说明超过 3 个簇后,聚类的业务逻辑和数据区分度已经大幅弱化;

        所有 K 值的轮廓系数均大于 0,说明没有出现 “样本聚类完全不合理” 的情况,整体聚类逻辑自洽。

3. 业务层面可解释性

        K=2 的聚类结果,本质是把 20 款啤酒清晰划分为两大核心品类,和啤酒行业的常规分类完全匹配:

        簇 1:常规全麦芽啤酒,卡路里、酒精度处于行业主流区间,代表样本为百威、喜力、麒麟等;

        簇 2:低卡淡爽型啤酒,卡路里、酒精度显著低于常规啤酒,主打轻饮健康定位,代表样本为 Miller Lite、Coors Light 等。

四、DBSCAN 算法核心原理详解

4.1 核心思想与基础概念

        DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是基于密度的带噪声的空间聚类算法。它将簇定义为密度相连的点的最大集合,能够把具有足够高密度的区域划分为簇,并且可以在带噪声的空间数据集中发现任意形状的聚类,完美弥补了 K-means 的核心短板。

其核心基础概念如下:

  • E 邻域:给定对象半径为 Eps 内的区域,称为该对象的 E 邻域
  • 核心对象:如果一个对象的 E 邻域内包含的样本数大于等于指定的密度阈值 MinPts,则该对象为核心对象
  • 直接密度可达:对于样本 A 和 B,如果 B 在 A 的 E 邻域内,且 A 是核心对象,则称 B 从 A 直接密度可达
  • 密度可达:对于样本链 A1,A2,...,An,若 Ai+1 从 Ai 直接密度可达,则称 An 从 A1 密度可达
  • 边界点:不是核心对象,但在某个核心对象的 E 邻域内的点
  • 离群点(噪声点):不与任何核心对象密度可达的点,既不是核心对象,也不是边界点

4.2 算法执行步骤

  1. 输入数据集,指定邻域半径 Eps 和密度阈值 MinPts
  2. 遍历数据集中的每个样本,判断其是否为核心对象
  3. 以所有核心对象为起点,找到所有密度可达的样本,划分为同一个簇
  4. 所有无法被划分到任何簇的样本,标记为离群点(噪声)

4.3 DBSCAN 优缺点

优点
  1. 不需要预先指定簇的数量 K,解决了 K-means 最核心的痛点
  2. 可以发现任意形状的簇,无论是球形、环形、带状,都能实现精准聚类
  3. 能够自动识别并标记离群点,对噪声数据不敏感
  4. 对初始值不敏感,聚类结果相对稳定,不会出现 K-means 因初始质心不同导致结果差异大的问题
缺点
  1. 对 Eps 和 MinPts 两个参数非常敏感,不同的参数组合会得到完全不同的聚类结果
  2. 当数据维度较高时,样本间的距离计算会出现 “维度灾难”,密度的定义变得困难
  3. 对于密度不均匀的数据集,聚类效果较差
  4. 计算效率相比 K-means 更低,不适合超大规模高维数据集

五、DBSCAN 算法 Python 实战(同啤酒数据集)

        为了和 K-means 做公平对比,我们使用同样的啤酒数据集实现 DBSCAN 聚类。

        注意:DBSCAN 基于距离计算,不同特征的量纲会严重影响距离结果,因此需要先对数据做标准化处理。

5.1 完整代码实现

from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler
import pandas as pd

beer = pd.read_table("data.txt", sep=" ", encoding="utf8")
X = beer[["calories", "sodium", "alcohol", "cost"]]
# 数据标准化,消除量纲影响
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 初始化DBSCAN模型,设置邻域半径和最小样本数
dbscan = DBSCAN(eps=1.0, min_samples=3)
# 训练模型并获取聚类标签
dbscan_labels = dbscan.fit_predict(X_scaled)

# 将聚类标签加入原数据集
beer["dbscan_cluster"] = dbscan_labels

# 输出聚类结果
print("DBSCAN聚类结果:")
print(beer[["name", "dbscan_cluster"]])
# 查看识别出的离群点(标签为-1的样本)
print("\nDBSCAN识别出的离群点:")
print(beer[beer["dbscan_cluster"] == -1][["name"]])

5.2 结果解读

DBSCAN 的聚类标签中,-1代表离群点,其他非负数值代表对应的簇编号。从运行结果可以看到:

1. 核心聚类结论

        模型无需预先指定簇数,自动将有效样本划分为 3 个核心簇(簇 0、簇 1、簇 2),同时识别出 6 个离群点(标签为 - 1),既完成了精细化品类划分,又实现了异常样本自动识别。

2. 各簇的业务特征解读

        3 个核心簇完全对应啤酒市场的真实品类分层,簇内样本特征高度一致:

        簇 0(大众主流平价啤酒):以百威、Schlitz、库尔斯等为代表,卡路里、钠含量、酒精度、价格均处于大众啤酒的主流区间,是市场占比最高的常规平价啤酒,样本密度最高、数量最多。

        簇 1(高端进口啤酒):以 Kronenbourg(1664)、Heineken(喜力)、Kirin(麒麟)为代表,酒精度中等偏高,价格显著高于大众啤酒,属于高端进口啤酒品类,特征区分度极强。

        簇 2(低卡轻饮啤酒):以 Miller Lite、Coors Light、Schlitz Light 等淡啤为代表,卡路里显著低于常规啤酒,酒精度偏低,主打低卡、轻饮的健康定位,和 K-means 识别出的低卡簇完全匹配,聚类精准度极高。

3. 离群点(异常样本)精准解读

        模型共识别出 6 个离群点,每个样本的异常原因均可对应数据特征,完全符合 DBSCAN 的密度判定逻辑:

  1. Lowenbrau:酒精度仅 0.9,远低于所有其他啤酒(其他样本酒精度最低 2.3,主流 4.0+),是最核心的全局异常值,和其他样本无密度连通性。
  2. Old_Milwaukee、Augsberger:钠含量、卡路里显著高于主流啤酒,同时价格极低,特征和常规啤酒差异过大,无法划入任何核心簇。
  3. Becks:虽属于高端啤酒,但特征和簇 1 的喜力、1664 等样本密度匹配度不足,被标记为边缘异常值。
  4. Pabst_Extra_Light、Olympia_Goled_Light:卡路里仅 68、72,是全样本卡路里最低的两款,和簇 2 的淡啤仍有显著特征差距,因此被识别为离群点。
4. 参数效果说明

       选用的eps=1.0、min_samples=3是适配当前标准化数据集的合理参数:既没有出现 “所有样本被划入一个簇” 的过拟合,也没有出现 “大部分样本被标记为离群点” 的欠拟合,完美平衡了聚类精度和异常识别能力。

六、K-means vs DBSCAN 核心对比

对比维度 K-means DBSCAN
核心思想 基于划分的聚类,最小化样本到质心的平方误差 基于密度的聚类,将密度相连的样本划分为同一个簇
核心输入参数 簇数量 K 邻域半径 Eps、密度阈值 MinPts
支持的簇形状 仅支持球形簇,对非球形簇效果极差 支持任意形状的簇
对异常值的处理 对异常值极度敏感,会严重干扰质心计算 自动识别并标记异常值,对噪声不敏感
初始值影响 对初始质心选择敏感,结果可能不稳定 对初始值不敏感,结果相对稳定
计算效率 高,适合大规模数据集 较低,不适合超大规模高维数据集
适用场景 数据分布呈球形、已知大概簇数量、无明显噪声的场景 数据分布不规则、有噪声、无法提前确定簇数量的场景

七、总结与拓展

        本文我们详细讲解了无监督学习中两大经典聚类算法 K-means 和 DBSCAN 的核心原理,基于啤酒数据集完成了完整的 Python 代码实战,通过轮廓系数为 K-means 选择了最优 K 值,对比了两种算法的核心差异与适用场景。

在实际的业务场景中,我们可以根据数据的特点灵活选择算法:

  • 如果你的数据是常规的球形分布,对计算效率要求高,并且能大致确定簇的数量,K-means 是非常好的选择
  • 如果你的数据分布不规则,存在大量噪声,并且无法提前确定簇的数量,DBSCAN 会更适合

        聚类算法作为无监督学习的核心,在用户分群、异常检测、图像分割、推荐系统等领域都有非常广泛的应用。后续我还会讲解更多聚类算法,比如层次聚类、高斯混合模型 GMM 等,敬请关注。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐