• KNN: 算点和点之间的距离(找邻居)。

  • K-Means: 算点和“质心(老大)”之间的距离(找组织)。

  • 推荐系统: 算你和商品之间的距离(猜你喜欢)。

  • 大模型(Transformer): 算词向量之间的距离(语义相似度)。

1. 算法核心思想

KMeans是一种无监督学习的聚类算法,通过迭代寻找K个簇的中心点,将数据划分到最近的簇中。不一定要找真正的中心点,是开数据关系盲盒。

2. 算法步骤

步骤1:初始化

随机选择K个点作为初始聚类中心(质心),或使用KMeans++算法:让初始中心点尽量分散开

步骤2:分配数据点

计算每个数据点到所有质心的距离(通常是欧氏距离),将每个数据点分配到最近的质心所属的簇

步骤3:更新质心

重新计算每个簇中所有点的平均值,将该平均值作为新的质心

步骤4:迭代

重复步骤2和3,直到:质心位置不再明显变化,达到最大迭代次数,簇的分配不再变化

3. 距离计算公式(欧氏距离)

对于两点 $p=(x_1, y_1)$ 和 $q=(x_2, y_2)$:
d(p,q)=(x1−x2)2+(y1−y2)2

4. 示例

假设我们有5个数据点,想分为2个簇(K=2):

X坐标 Y坐标
A 1.0 1.0
B 1.5 2.0
C 3.0 4.0
D 5.0 7.0
E 3.5 5.0
第1次迭代:初始化

随机选择初始质心(假设选A和C):

  • 质心1:C1 = A(1.0, 1.0)

  • 质心2:C2 = C(3.0, 4.0)

计算距离并分配簇:

点到C1(1.0,1.0)的距离:

  • A: √[(1-1)² + (1-1)²] = 0

  • B: √[(1.5-1)² + (2-1)²] = √(0.25+1) = √1.25 ≈ 1.12

  • C: √[(3-1)² + (4-1)²] = √(4+9) = √13 ≈ 3.61

  • D: √[(5-1)² + (7-1)²] = √(16+36) = √52 ≈ 7.21

  • E: √[(3.5-1)² + (5-1)²] = √(6.25+16) = √22.25 ≈ 4.72

点到C2(3.0,4.0)的距离:

  • A: √[(1-3)² + (1-4)²] = √(4+9) = √13 ≈ 3.61

  • B: √[(1.5-3)² + (2-4)²] = √(2.25+4) = √6.25 = 2.5

  • C: 0

  • D: √[(5-3)² + (7-4)²] = √(4+9) = √13 ≈ 3.61

  • E: √[(3.5-3)² + (5-4)²] = √(0.25+1) = √1.25 ≈ 1.12

分配结果:

  • A: 距离C1(0) < 距离C2(3.61) → 簇1

  • B: 距离C1(1.12) < 距离C2(2.5) → 簇1

  • C: 距离C1(3.61) > 距离C2(0) → 簇2

  • D: 距离C1(7.21) > 距离C2(3.61) → 簇2

  • E: 距离C1(4.72) > 距离C2(1.12) → 簇2

簇分配:

  • 簇1:A(1.0,1.0), B(1.5,2.0)

  • 簇2:C(3.0,4.0), D(5.0,7.0), E(3.5,5.0)

第2次迭代:更新质心

计算新质心:

  • 新C1 = [(1.0+1.5)/2, (1.0+2.0)/2] = (1.25, 1.5)

  • 新C2 = [(3.0+5.0+3.5)/3, (4.0+7.0+5.0)/3] = (11.5/3, 16/3) ≈ (3.83, 5.33)

重新计算距离并分配...

这个过程会持续迭代,直到质心位置稳定。

数据太多,是因为标准 K-Means 每一轮迭代都要算 所有点 到质心的距离。如果有 1 亿条数据,算一次就得累死。

工业界的解法: Mini-Batch K-Means(小批量 K-Means)

  • 我不算 1 亿个点。

  • 我每次随机抽 1000 个点(Batch)

  • 我只用这 1000 个点来更新质心。

  • 多跑几轮,质心基本上就稳定了。

  • 速度: 快了 100 倍甚至 1000 倍。

  • 精度: 会稍微差一丢丢(因为是抽样),但在商业上完全够用。

实现代码

def dm01_kmeans():
    # 1 导入依赖包
    from sklearn.cluster import KMeans
    import matplotlib.pyplot as plt
    from sklearn.datasets import make_blobs
    # make系列-自己构造数据集 fetch系列大数据-从网络加载 load系列小数据集-从本地数据集
    from sklearn.metrics import calinski_harabasz_score  # calinski_harabaz_score 废弃

    # 2 创建数据集 1000个样本,每个样本2个特征 4个质心蔟数据标准差[0.4, 0.2, 0.2, 0.2]
    x, _ = make_blobs(
        n_samples=1000,
        n_features=2,
        centers=[[-1, -1], [0, 0], [1, 1], [2, 2]],
        cluster_std=[0.4, 0.2, 0.2, 0.2],
        random_state=22
    )

    print(f"x = {x}")

    plt.figure()
    plt.scatter(x[:, 0], x[:, 1], marker='o')
    plt.show()

    # 3 使用k-means进行聚类, 并使用CH方法评估
    # 3-1 n_clusters=2 两个初始点
    # init='k-means++', 智能初始化,避免局部最优,让初始中心尽量分散开,而不是随机乱选,分散得越开越好。这样分类效率最高,收敛最快,不容易出错。让n_clusters指定的那个两个初始点不要聚在一起
    # n_init = 'auto', 自动选择尝试次数,平衡效果效率
    # random_state = 22  可重复性,固定种子,保证每次运行结果一模一样
    y_pred = KMeans(n_clusters=2, random_state=22, init='k-means++', n_init='auto').fit_predict(x)
    plt.scatter(x[:, 0], x[:, 1], c=y_pred)
    plt.show()
    print('1-->', calinski_harabasz_score(x, y_pred))

    # 3-2 n_clusters=3
    y_pred = KMeans(n_clusters=3, random_state=22, n_init='auto').fit_predict(x)
    plt.scatter(x[:, 0], x[:, 1], c=y_pred)
    plt.show()
    print('2-->', calinski_harabasz_score(x, y_pred))

    # 3-3 n_clusters=4
    # init='k-means++':聪明的初始化策略
    estimator = KMeans(n_clusters=4, random_state=22, n_init='auto')
    y_pred = estimator.fit_predict(x)
    plt.scatter(x[:, 0], x[:, 1], c=y_pred)
    plt.show()

    # 4 模型评估
    print('3-->', calinski_harabasz_score(x, y_pred))


if __name__ == '__main__':
    dm01_kmeans()

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐