大数跨境

一个强大算法模型,层次聚类 !!

一个强大算法模型,层次聚类 !! 机器学习和人工智能AI
2026-09-01
4

哈喽,大家好~

今天我们来聊一个非常直观的无学习算法,层次聚类

它不仅能给出聚类结果,还会完整保留样本从独立个体到逐步合并的过程。

层次聚类是什么

普通聚类更像直接告诉我们:“这些样本分成了4组。”

层次聚类则会继续解释:谁先和谁合并,哪些小组又组成了更大的组。

它主要有两种方式:

  • 凝聚式聚类:每个样本最开始都是一类,然后不断合并,使用最广泛。
  • 分裂式聚类:所有样本最开始属于一类,再逐层拆分。

我们这里使用凝聚式聚类。你可以把它想成公司组建团队:先让最相似的两个人组队,再让相近的小队组成部门,最后形成完整组织。

核心原理:两个簇到底有多近

算法每次都要找出距离最近的两个簇,但“簇之间的距离”有不同定义。

Single Linkage 取两个簇中最近样本的距离:

Complete Linkage 取最远样本的距离,而 Average Linkage 使用所有样本距离的平均值。

实际中常用的 Ward 方法稍有不同,它选择合并后类内平方误差增加最少的两个簇:

其中, 表示两个簇的样本数量, 是簇中心。

一句话概括:Ward 方法会尽量让同一类中的样本保持紧凑。

所有合并过程可以画成树状图。树枝连接得越低,表示两组样本越相似;在某个高度画一条横线,切出几根主树枝,就能得到几个类别。

Python完整案例

下面构造一份客户数据。横轴表示消费能力,纵轴表示活跃程度,同时加入不同方差、旋转结构和少量噪声,让数据更接近真实场景。

通过下面两幅图帮助大家理解~

  1. 层次聚类树状图:观察样本合并过程;
  2. 聚类诊断图:同时展示聚类边界、簇中心和每类轮廓系数。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics import silhouette_samples, silhouette_score
from scipy.cluster.hierarchy import linkage, dendrogram
from scipy.spatial import ConvexHull

np.random.seed(42)

# 1. 生成不同密度的客户数据
X, _ = make_blobs(
    n_samples=360,
    centers=[(-4-1), (-13), (32), (4-2)],
    cluster_std=[0.651.050.751.20],
    random_state=42
)

# 旋转和拉伸,构造非规则分布
transform = np.array([[1.00.65], [-0.251.15]])
X = X @ transform

# 添加少量噪声客户
noise = np.random.uniform(X.min(axis=0), X.max(axis=0), (202))
X = np.vstack([X, noise])
X = StandardScaler().fit_transform(X)

# 2. Ward层次聚类
model = AgglomerativeClustering(n_clusters=4, linkage="ward")
labels = model.fit_predict(X)

# scipy linkage用于绘制树状图
Z = linkage(X, method="ward")
cut_height = (Z[-42] + Z[-32]) / 2

plt.style.use("dark_background")
colors = ["#00F5D4""#F15BB5""#FEE440""#00BBF9"]

# 图1:截断树状图
plt.figure(figsize=(126))
dendrogram(
    Z,
    truncate_mode="lastp",
    p=28,
    leaf_rotation=0,
    leaf_font_size=10,
    show_contracted=True,
    color_threshold=cut_height
)
plt.axhline(cut_height, color="#FF4D6D", linestyle="--",
            linewidth=2, label="4类切割线")
plt.title("Hierarchical Clustering Dendrogram", fontsize=16)
plt.xlabel("合并后的样本簇")
plt.ylabel("Ward合并距离")
plt.legend()
plt.tight_layout()
plt.show()

# 3. 计算轮廓系数
sample_scores = silhouette_samples(X, labels)
avg_score = silhouette_score(X, labels)

# 图2:聚类空间 + 轮廓系数联合诊断
fig, axes = plt.subplots(12, figsize=(156))

# 左图:聚类结果、中心与凸包边界
for k, color in enumerate(colors):
    points = X[labels == k]
    axes[0].scatter(
        points[:, 0], points[:, 1],
        s=38, color=color, alpha=0.82,
        edgecolor="white", linewidth=0.25
    )

    center = points.mean(axis=0)
    axes[0].scatter(
        center[0], center[1],
        marker="*", s=350, color="white",
        edgecolor=color, linewidth=2.5
    )

    if len(points) >= 3:
        hull = ConvexHull(points)
        boundary = points[hull.vertices]
        axes[0].fill(
            boundary[:, 0], boundary[:, 1],
            color=color, alpha=0.10
        )
        axes[0].plot(
            np.r_[boundary[:, 0], boundary[00]],
            np.r_[boundary[:, 1], boundary[01]],
            color=color, linewidth=1.5
        )

axes[0].set_title("客户聚类空间:颜色、中心与边界")
axes[0].set_xlabel("标准化消费能力")
axes[0].set_ylabel("标准化活跃程度")
axes[0].grid(alpha=0.15)

# 右图:每个簇的轮廓系数
y_lower = 10
for k, color in enumerate(colors):
    values = np.sort(sample_scores[labels == k])
    y_upper = y_lower + len(values)

    axes[1].fill_betweenx(
        np.arange(y_lower, y_upper),
        0, values, color=color, alpha=0.9
    )
    axes[1].text(-0.08, (y_lower + y_upper) / 2f"C{k}")
    y_lower = y_upper + 10

axes[1].axvline(
    avg_score, color="#FF4D6D", linestyle="--",
    linewidth=2, label=f"平均值={avg_score:.3f}"
)
axes[1].axvline(0, color="white", linewidth=1)
axes[1].set_title("各簇轮廓系数诊断")
axes[1].set_xlabel("Silhouette Score")
axes[1].set_ylabel("簇内样本")
axes[1].legend()

plt.tight_layout()
plt.show()

print(f"整体轮廓系数:{avg_score:.3f}")

第一张树状图记录了整个合并过程。红色虚线相当于拿一把剪刀横着剪树,虚线下方形成的4根主要树枝,就对应4个客户群体。

虚线附近如果存在明显的高度空档,说明从4类继续合并到3类需要付出较大的类内误差,选择4类就比较合理。

第二张图是更完整的聚类诊断。左侧不同颜色代表不同客户群,白色星号是簇中心,半透明区域是每一类的空间边界。边界大量重叠时,说明类别不容易区分。

右侧是轮廓系数,其取值范围为 。越接近1,说明样本更适合当前类别;接近0表示它处在两个簇的边界;小于0则意味着它很可能被分错了。

因此,不要只看散点图“颜色分得好不好看”,还要结合树状图和轮廓系数判断结果是否可靠。

注意点

层次聚类对特征尺度非常敏感。收入以万元计算、访问次数以个位数计算时,收入会直接主导距离,所以代码中先使用了StandardScaler

Ward适合数值型数据和相对紧凑的簇;如果数据是弯月形、链条形,可以尝试singleaverage。类别数量也不要凭感觉决定,可以同时比较树状图、业务需求和不同 值下的轮廓系数。

另外,层次聚类通常需要保存样本间距离,数据量很大时内存压力明显。它更适合中小规模数据的探索分析,而不是直接处理百万级样本。

总结

层次聚类的核心,就是不断合并距离最近的簇,并把整个过程保存成一棵树。它最大的价值不只是“完成分组”,而是让我们看见数据从局部到整体的组织关系。

【声明】内容源于网络
0
0
机器学习和人工智能AI
让我们一起期待 AI 带给我们的每一场变革!推送最新行业内最新最前沿人工智能技术!
内容 381
粉丝 0
机器学习和人工智能AI 让我们一起期待 AI 带给我们的每一场变革!推送最新行业内最新最前沿人工智能技术!
总阅读5.0k
粉丝0
内容381