【数学建模学习笔记】无监督聚类模型:分层聚类

发布于:2025-09-04 ⋅ 阅读:(21) ⋅ 点赞:(0)

零基础看懂用 Pandas 做层次聚类:从概念到实操

如果你是刚接触数据分析的 “小白”,不用怕!这篇内容会用最通俗的语言,把 “用 Pandas 做层次聚类” 的核心逻辑、步骤和结果讲明白,帮你轻松入门。

一、先搞懂:什么是层次聚类?

简单说,层次聚类就是给数据 “分层次抱团”—— 就像一群人按兴趣组队,先让每个人自成一队,再慢慢把兴趣最像的小队合并,直到最后所有小队合成一个大团队;或者反过来,先把所有人当一个大团队,再慢慢拆成小团队。

它主要分两种方式:

  • 自底向上(凝聚法):从 “最小单位” 开始合并(比如 1 个样本 = 1 个类),这是我们这次实验用的方法,更简单、常用。
  • 自顶向下(分裂法):从 “最大单位” 开始拆分(比如所有样本 = 1 个类),难度稍高,小白先聚焦凝聚法即可。

二、我们要解决什么问题?用什么数据?

1. 问题目标

分析不同地区的 “居民支出结构”,看看哪些地区的支出习惯更像,把它们归为一类。

2. 数据介绍

我们用了一份 “各地区居民支出” 的数据,包含 30 个地区(比如北京、天津、河北等),每个地区有 6 个 “支出指标”:

列名 含义 比如(北京的数据)
地区 城市 / 省份名称 北京
食品(X1) 食品支出金额 190.33(单位:元)
衣食(X2) 衣物支出金额 43.77
燃料(X3) 燃气、电费等支出 9.73
住房(X4) 住房相关支出 60.54
生活用品(X5) 日用品支出 49.01
文化服务(X6) 娱乐、教育等支出 9.04

简单理解:每个地区就像一个 “学生”,6 项支出就是这个学生的 “6 门成绩”,我们要按 “成绩相似性” 给学生分班(聚类)。

三、实操步骤:一步一步做聚类

接下来的每一步,都像搭积木一样简单,我们会先讲 “为什么要做”,再讲 “代码在干什么”。

步骤 1:准备 “工具”(导入库)

就像做饭要先拿锅碗瓢盆,做数据分析要先导入 “工具库”,每个库有专门用途:

import numpy as np       # 处理数字、计算的工具
import pandas as pd      # 读取、整理数据的核心工具(本次主角)
import matplotlib.pyplot as plt # 画图用的工具(最后看聚类结果)
from scipy.cluster.hierarchy import dendrogram, linkage # 做层次聚类的工具
from sklearn.preprocessing import StandardScaler # 数据“标准化”的工具

步骤 2:读入数据

用 Pandas 把刚才说的 “地区支出数据” 读进来,方便后续分析:

# 从网上读取Excel数据,存到“df”这个表格里
df = pd.read_excel('https://labfile.oss.aliyuncs.com/courses/40611/%E5%88%86%E5%B1%82%E8%81%9A%E7%B1%BB.xlsx')
df.head() # 显示前5行数据,确认数据读对了

运行后会看到北京、天津、河北等前 5 个地区的支出数据,和我们前面表格里的内容一致。

步骤 3:数据 “标准化”—— 关键一步!

为什么要标准化?

比如 “食品支出” 普遍是 100 元左右,“文化服务支出” 普遍是 3-9 元,两者数值差距很大。如果直接计算相似度,“食品支出” 的影响会被放大(比如 10 元的差距在食品里不算大,但在文化支出里就是翻倍),导致聚类结果不准。

标准化的作用:把所有指标 “拉到同一水平”(比如都变成平均值为 0、标准差为 1 的数),让每个指标对聚类的影响公平。

代码怎么做?
# 1. 去掉“地区”列(因为“地区”是名字,不是要计算的数值)
# 2. 用StandardScaler工具对剩下的6项支出做标准化
scaler = StandardScaler()
df_scaled = scaler.fit_transform(df.drop('地区', axis=1))

运行后,df_scaled就是标准化后的 6 项支出数据,虽然数值变了,但各地区的 “支出比例关系” 没变。

步骤 4:核心!做层次聚类

聚类的 “核心逻辑”(凝聚法)

就 3 步,循环到结束:

  1. 初始化:每个地区算 1 个 “小类”(比如 30 个地区 = 30 个类);
  2. 找相似:计算所有小类之间的 “距离”(距离越近 = 支出习惯越像),把最近的两个小类合并成 1 个 “新类”;
  3. 重计算:重新计算 “新类” 和其他所有类的距离;
  4. 循环:重复步骤 2-3,直到所有地区合并成 1 个大类。
代码怎么做?
# linkage:实现层次聚类的核心函数
# df_scaled:用标准化后的数据
# method='ward':一种常用的“计算类距离”的方法(让每个类内部的差异尽可能小)
linked = linkage(df_scaled, method='ward')

运行后,linked里就存了所有 “合并类” 的过程(比如哪两个类先合并、合并时的距离是多少)。

步骤 5:看结果!画 “树状图”

聚类结果不能只看数字,画个 “树状图”(dendrogram)最直观,能清楚看到 “谁和谁先抱团”。

代码画图:
# 创建一个画图窗口(10x7是窗口大小,单位:英寸)
plt.figure(figsize=(10, 7))
# 画树状图
dendrogram(linked,
           orientation='top',  # 树的方向:从上往下画
           distance_sort='descending', # 按距离从大到小排序
           show_leaf_counts=True) # 显示每个分支的样本数
plt.xlabel('Index') # X轴:数据的序号(对应每个地区)
plt.ylabel('Distance') # Y轴:距离(越高=越晚合并,相似度越低)
plt.show() # 显示图片
怎么看树状图?
  • 最下面的 “小横线”:每个代表 1 个地区(序号对应 X 轴);
  • 往上的 “横线”:代表 “合并类” 的操作 —— 横线越短,说明合并的两个类相似度越高;
  • 中间画一条 “竖线”(比如 Y=6.5 的位置):竖线穿过几条横线,就把数据分成几类。

比如实验里说 “在距离 6.5 左右分成两类”:树状图里 Y=6.5 的竖线会把所有分支分成两大块,一块是橙色,一块是绿色,对应的地区就是两类 —— 橙色里的地区支出习惯相似,绿色里的也相似。

四、关键补充:怎么判断 “类的相似度”?

前面提到method='ward',其实还有其他判断 “类距离” 的方法,就像 “判断两个球队像不像”,可以看最像的球员、最不像的球员,等等:

  1. Single Linkage(单链接):看两个类里 “最近的两个样本” 的距离(比如 A 类里最瘦的和 B 类里最瘦的体重差);
  2. Complete Linkage(全链接):看两个类里 “最远的两个样本” 的距离(比如 A 类里最胖的和 B 类里最胖的体重差);
  3. Average Linkage(平均链接):看两个类里 “所有样本两两距离的平均值”(比如 A 类和 B 类所有人的体重差求平均);
  4. Centroid Linkage(中心链接):看两个类 “中心” 的距离(比如 A 类的平均体重和 B 类的平均体重差);
  5. Ward Linkage(沃德法):让合并后 “类内部的总差异最小”(最常用,聚类效果更稳定)。

五、总结:层次聚类适合什么场景?

  1. 优点:简单直观,能通过树状图看到完整的聚类过程,不用提前指定 “分几类”(看树状图的横线高度就能定);
  2. 缺点:数据量大时(比如几万个样本)会很慢,适合 “小样本数据集”(比如我们这次 30 个地区);
  3. 用在哪:比如分客户群体(按消费习惯聚类)、分产品类别(按销量特征聚类)、分地区(按经济指标聚类)等。

网站公告

今日签到

点亮在社区的每一天
去签到