CHAPTER 29 / 37
聚类:当数据没有答案时,我们如何发现结构?
当我们停止追问答案时,数据才开始向我们展示它真正的结构。在没有标签的世界里,最重要的能力不是判断对错,而是看见秩序。
在前28篇文章里,我们一直在讨论一种非常典型的机器学习范式:监督学习(Supervised Learning)。
你给模型一堆数据,同时也给它标准答案。模型的任务,是学会从输入到输出的映射关系。比如输入:用户行为数据,输出:是否会流失;输入:车辆传感器数据,输出:是否存在风险……本质上都是:给定问题,寻找答案。
但从今天开始,我们进入一个完全不同的世界。
这个世界没有标准答案,甚至问题本身,也不一定是清晰的。
什么是无监督学习?
先给一个非常工程化的定义:无监督学习(Unsupervised Learning),就是在没有标签的情况下,从数据中自动发现结构。
注意这里的关键词:结构(Structure)。不是预测,不是分类,不是判断对错。而是:这堆数据,里面到底有什么规律?
假设你是一个电商平台的产品负责人。你有一批用户数据:
年龄
购买频率
客单价
浏览时间退
款次数但你没有:
用户类型标签
用户价值等级
用户画像分类这时候,你会很自然地产生一个问题:这些用户,是不是天然可以分成几类?比如:
高频低价用户
低频高价用户
浏览很多但不买的用户
新用户但注意,这些标签是你猜的,并没有人告诉你答案。
这就是典型的聚类(Clustering)问题。
什么是聚类(Clustering)?
再给一个工程上最实用的定义:聚类,就是把“相似的数据”自动分成一组一组。
非常像现实世界里的行为——人会自动把衣服按颜色放一起,图书馆会把书按主题放一起,超市会把商品按类别放一起。
但这里有一个关键区别:机器不是按“名字”分组,而是按“相似度”分组。
假设你在做一个智能座舱系统,系统收集到一堆驾驶行为数据:
平均车速
急刹次数
夜间驾驶比例
音乐音量
导航使用频率你没有“驾驶风格标签”,但你想知道用户是不是自然分成几类驾驶风格?
聚类算法可能会自动发现:
第一类:高速驾驶、夜间比例高、音乐音量大。可能是:年轻驾驶者
第二类:车速稳定、很少急刹、导航使用频繁。可能是:通勤用户
这就是:从数据中发现结构而不是:预测答案
聚类最重要的一种算法:K-means
在所有聚类算法中,最经典、最常用、最容易理解的一种,叫:K-means。
它几乎是聚类领域的“Hello World”。K-means简单来说,就是在不断移动“中心点”,让所有数据离它们更近。
假设你开了一家咖啡店,你有一份客户地址数据,你想在城市里开两个门店。你的目标是让所有客户离门店尽量近。这时候你会怎么做?大概率是:
第一步:先随便选两个位置。
第二步:看每个客户更接近哪个门店。
第三步:把门店移动到这些客户的“平均位置”。
然后:重复。
这就是:K-means 的全部逻辑,非常简单,甚至有点像常识。
K-means 的核心循环:只有两步
这是整个算法最重要的地方。你只需要记住:
Step 1:分配(Assign)每个数据点:选择离它最近的中心。
比如:
用户 A: 离中心 1 更近 → 归到 cluster 1
用户 B: 离中心 2 更近 → 归到 cluster 2这一步,本质是找最近的中心。
Step 2:更新(Move)
对每个 cluster 重新计算所有数据点的平均位置,然后把中心移动到这个平均位置。 这两个动作会一直重复:
分配 → 更新
分配 → 更新
分配 → 更新
……直到再怎么更新,结果都不会变,这就叫:收敛(Converge)。
这正是 K-means 的核心机制:它会不断执行“分配数据点到最近中心”和“把中心移动到这些点的平均位置”这两个步骤,直到没有变化为止。
可以通过下述代码,感受下在TensorFlow中的实现:
import tensorflow as tf
import numpy as np
# 模拟数据:用户消费金额 & 访问频率
data = np.array([
[100, 5],
[120, 6],
[500, 1],
[550, 2],
[90, 7],
[600, 1]
])
k = 2
kmeans = tf.compat.v1.estimator.experimental.KMeans(
num_clusters=k,
use_mini_batch=True
)
def input_fn():
return tf.data.Dataset.from_tensor_slices(data).repeat(10)
kmeans.train(input_fn)
clusters = list(kmeans.predict_cluster_index(input_fn))
print(clusters)为什么 K-means 一定会停下来?
这是一个很多人第一次学时会问的问题——它会不会一直算下去?答案是:不会。
因为 K-means 实际上在优化一个非常明确的目标函数:让所有点,离自己的中心尽量近。
换句话说,它在最小化“所有数据点到所属中心的平方距离平均值”这个目标函数,这个函数也有一个很学术的名字——Distortion Function(失真函数)。
每执行一次分配——更新的过程,这个值都要么下降,要么不变,而永远不会上升。 所以最终一定会停。
初始化
K-means 有一个非常微妙但非常重要的问题:初始中心,是随机的。
这意味着同一份数据,你可能会得到完全不同的结果。
假设你在做用户分群,你想分 3 类用户。
如果初始中心恰好选得好,你可能得到:
高价值用户、中价值用户、低价值用户但如果选得不好,你可能得到:
一堆混合用户、一堆边缘用户、一堆异常用户这叫局部最优(Local Optimum)。
工程上最常见的解决方案非常简单——多跑几次,选最好的。
比如运行 100 次,每次随机初始化,选择损失最小的结果,这是业界非常标准的做法。
K 应该等于多少?
这是一个非常现实的问题——要分几类?
比如用户分群,你可以分成 2 类、 3 类、 5 类、 10 类……都可能是对的。 因为聚类,本来就没有标准答案。
一个非常典型的工程思路不是问数据里有几类? 而是问我业务上需要几类?
比如服装公司,你可以分成:S、M、L ,也可以分成:XS、S、M、L、XL 。两个方案都合理。 但:
多尺寸 → 更贴合用户
少尺寸 → 更省成本因此决定最终选择的,不是数学问题,而是业务问题。
这正是实际工程中选择 K 的常见方式——根据后续业务用途,而不是单纯依赖数学指标。
很多人第一次接触聚类,会觉得它很数学。但如果你从产品角度看,它其实非常直观。因为它解决的是一个极其常见的问题——在没有标签的时候,如何理解用户?
这件事,在现实世界里每天都在发生:用户画像、客户分层、内容推荐、风险识别、驾驶行为分析、设备异常检测……几乎所有数据产品,都会用到聚类。
今天这篇文章,你只需要记住三件事:
1、聚类,不是预测,而是发现结构。不是判断对错,而是判断这堆数据里面有什么规律?
2、K-means只有两个动作——分配和更新,并反复执行,直到稳定。
3、最难的问题不是算法,而是分几类?而这是业务问题,不是技术问题。
附录:本文涉及的专有名词中英文对照(标红为最核心)