2、聚类算法基础:K-Means原理、层次聚类原理、DBSCAN原理、聚类评价指标

好,咱们进入正题。这一章讲的是聚类算法的基础,说白了就是教计算机怎么把一堆数据自动分成几堆。在行业轮动里,我们经常需要把不同行业按照某些特征(比如收益率、波动率)自动归类,这时候聚类就派上用场了。

我个人习惯把聚类算法分成三大类:基于划分的、基于层次的、基于密度的。咱们一个一个来聊。

2.1 K-Means原理

K-Means 是最经典的聚类算法,没有之一。它的思路特别简单:

  1. 先随便选 K 个点作为初始中心
  2. 把每个数据点分给离它最近的中心
  3. 重新计算每个簇的中心(取均值)
  4. 重复第2、3步,直到中心不再变化

嗯,就这么简单。但简单不代表没用。我在做行业轮动策略时,经常用 K-Means 把行业按历史收益率聚类,效果还不错。

关键点:K 值需要提前指定。怎么选?后面会讲轮廓系数和 CH 指数,就是用来干这个的。

不过 K-Means 有个坑:它对初始中心的选择很敏感。你想想看,如果初始中心选得不好,可能就掉进局部最优了。我曾经遇到过这种情况,同样的数据跑两次,结果完全不一样。后来我习惯用 K-Means++ 初始化,能稳定不少。

# 一个简单的 K-Means 示例
from sklearn.cluster import KMeans
import numpy as np

# 假设我们有 100 个行业样本,每个样本有 2 个特征
X = np.random.rand(100, 2)
kmeans = KMeans(n_clusters=5, random_state=42)
kmeans.fit(X)

# 获取聚类标签
labels = kmeans.labels_
centers = kmeans.cluster_centers_
print("聚类中心:\n", centers)

我的小技巧:用 K-Means 之前,最好先做标准化。不然量纲大的特征会主导距离计算,结果就偏了。

2.2 层次聚类原理

层次聚类,说白了就是构建一棵树。它有两种方式:

  • 自底向上(凝聚式):每个点先自成一类,然后不断合并最近的两类
  • 自顶向下(分裂式):所有点先是一类,然后不断分裂

实际中我几乎只用凝聚式。为什么?因为它更直观,而且计算量相对可控。

层次聚类的好处是,你不用事先指定 K 值。跑完之后看树状图,想分几类就切几刀。我在做行业分类时,经常先用层次聚类看看数据的大致结构,再决定用 K-Means 还是别的。

注意:层次聚类的计算复杂度是 O(n³),数据量大了跑不动。我一般只在样本数小于 1000 的时候用它。

# 层次聚类示例
from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.pyplot as plt

# 生成数据
X = np.random.rand(20, 2)

# 计算连接矩阵
Z = linkage(X, method='ward')

# 画树状图
plt.figure(figsize=(10, 5))
dendrogram(Z)
plt.title("层次聚类树状图")
plt.show()

2.3 DBSCAN原理

DBSCAN 是个狠角色。它不要求你指定 K 值,还能发现任意形状的簇,甚至能识别出异常点。

它的核心思想是:如果一个点周围足够密(半径 ε 内有至少 minPts 个点),那它就是一个核心点。核心点连在一起就形成簇。

我记得有一次做行业轮动,数据里有一些行业表现特别异常(比如金融危机时的银行股),用 K-Means 死活分不好。换成 DBSCAN 后,那些异常点直接被标为噪声,剩下的正常行业聚类效果好了很多。

两个关键参数:

  • eps(ε):邻域半径。太小了容易把簇拆散,太大了容易合并
  • minPts:最小样本数。一般取数据维度的两倍

避坑指南:我曾经把 eps 设得太小,结果大部分点都成了噪声。后来我习惯先画个 k-distance 图,找到拐点作为 eps 的参考值。

# DBSCAN 示例
from sklearn.cluster import DBSCAN

# 假设数据
X = np.random.rand(100, 2)

# 创建 DBSCAN 模型
db = DBSCAN(eps=0.3, min_samples=5)
labels = db.fit_predict(X)

# 标签为 -1 的是噪声点
n_noise = list(labels).count(-1)
print(f"噪声点数量: {n_noise}")

2.4 聚类评价指标

聚类做完了,怎么评价好坏?这是个好问题。因为聚类是无监督学习,没有真实标签,所以评价起来比较麻烦。

我常用的两个指标:

轮廓系数(Silhouette Coefficient)

轮廓系数衡量的是:一个样本与它自己簇的相似度,以及与其他簇的差异度。取值范围 [-1, 1],越大越好。

  • 接近 1:样本离自己簇很近,离其他簇很远
  • 接近 0:样本在两个簇的边界上
  • 接近 -1:样本可能分错了簇

我的经验:轮廓系数大于 0.5 就算不错了。在行业轮动中,我一般要求至少 0.4 以上,否则聚类结果不太可信。

CH指数(Calinski-Harabasz Index)

CH 指数的思路是:簇间距离越大越好,簇内距离越小越好。它计算的是簇间离散度与簇内离散度的比值。

说白了,就是看簇与簇之间分得开不开,每个簇内部紧不紧。CH 指数越大,聚类效果越好。

指标 优点 缺点
轮廓系数 直观,能看出单个样本的质量 计算量大,对凸簇更有效
CH指数 计算快,适合大数据 对非凸簇效果差
# 计算轮廓系数和 CH 指数
from sklearn.metrics import silhouette_score, calinski_harabasz_score

# 假设已有聚类结果
X = np.random.rand(100, 2)
labels = KMeans(n_clusters=5, random_state=42).fit_predict(X)

# 轮廓系数
sil_score = silhouette_score(X, labels)
print(f"轮廓系数: {sil_score:.3f}")

# CH 指数
ch_score = calinski_harabasz_score(X, labels)
print(f"CH 指数: {ch_score:.3f}")

注意:这两个指标都是基于距离的,所以数据标准化很重要。另外,它们都偏向于凸形簇,如果数据是长条形的,结果可能不太准。

知识体系总览

下面这张图把本章的核心逻辑串起来了,你可以对照着看:

聚类算法知识体系 K-Means 层次聚类 DBSCAN 需指定K值 对初始值敏感 适合凸形簇 不需指定K值 可看树状图 计算量大 不需指定K值 可识别噪声 参数敏感 评价指标:轮廓系数 | CH指数 选择算法时:数据量大用K-Means,想探索结构用层次聚类,有噪声用DBSCAN

好了,这一章的内容就这些。聚类算法是行业轮动策略的基础工具,掌握了这些,后面咱们就能用它们来给行业分组了。


专注资料整理