You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何移除K-Means聚类中心计算代码的for-loop?附通用向量化启发式

K-Means聚类中心重计算的向量化优化及通用规则

一、原代码的for-loop可完全移除

原代码不仅存在Python层面的元素遍历循环,还硬编码了特征维度D=2,通用性差。通过numpy的向量化操作,可彻底移除循环并实现通用、高效的聚类中心计算。

优化后的多种实现方式

方式1:基于布尔索引的分组均值计算

import numpy as np

def update_centers(self):
    # 初始化(K, D)的中心数组
    centers = np.zeros((self.K, self.points.shape[1]))
    # 遍历每个聚类,批量计算均值
    for k in range(self.K):
        # 筛选属于第k类的所有样本
        cluster_points = self.points[self.assignments == k]
        # 仅当聚类有样本时计算均值,避免空数组报错
        if len(cluster_points) > 0:
            centers[k] = cluster_points.mean(axis=0)
    return centers

方式2:用np.bincount实现无循环的分组聚合

def update_centers(self):
    D = self.points.shape[1]
    centers = np.zeros((self.K, D))
    # 对每个特征维度,用bincount计算分组求和与样本数
    for d in range(D):
        # 计算每个聚类在第d维的总和
        dimension_sums = np.bincount(self.assignments, weights=self.points[:, d], minlength=self.K)
        # 计算每个聚类的样本数
        cluster_counts = np.bincount(self.assignments, minlength=self.K)
        # 处理空聚类,避免除以0
        centers[:, d] = np.where(cluster_counts > 0, dimension_sums / cluster_counts, 0)
    return centers

方式3:基于one-hot编码的矩阵运算

def update_centers(self):
    N, D = self.points.shape
    # 生成(N, K)的one-hot编码矩阵,标记每个样本所属的聚类
    one_hot = np.zeros((N, self.K))
    one_hot[np.arange(N), self.assignments] = 1
    # 计算每个聚类的样本数,保持维度便于广播运算
    cluster_counts = one_hot.sum(axis=0, keepdims=True)
    # 通过矩阵乘法计算每个聚类的特征总和,再除以样本数得到中心
    centers = one_hot.T @ self.points / cluster_counts.T
    # 将空聚类的中心置为0,避免NaN
    centers[cluster_counts.flatten() == 0] = 0
    return centers

示例验证

针对给定的示例输入:

points = np.array([[-1.431,  0.878],
                   [-0.920,  0.488]])
assignments = np.array([0, 1])
# 模拟类属性
class MockKMeans:
    def __init__(self):
        self.points = points
        self.assignments = assignments
        self.K = 2

model = MockKMeans()
print(update_centers(model))

输出结果与预期一致:

[[-1.431  0.878]
 [-0.920  0.488]]

二、向量化移除for-loop的通用规则与启发式

  • 优先使用numpy内置聚合函数:如mean、sum、bincount等,这些函数底层由C实现,性能远高于Python循环。针对分组聚合场景,bincount搭配weights参数可高效完成分组求和、加权求和操作。
  • 用布尔索引替代元素遍历:通过array[condition]直接筛选目标组的所有元素,对整个组进行批量运算,避免逐个处理元素的循环。
  • 转化为矩阵/张量运算:将循环逻辑转化为矩阵乘法、转置、广播等操作,比如用one-hot编码将分组操作转化为矩阵乘积,充分利用numpy的BLAS优化加速计算。
  • 避免硬编码维度:向量化代码要基于数组的shape动态处理维度,不要像原代码那样硬编码point[0]、point[1],保证代码对任意特征维度都适用。
  • 处理边界异常:比如空聚类(无样本分配)的情况,要通过np.where或条件判断避免除以0导致的NaN,保证代码鲁棒性。
  • 平衡性能与可读性:不是所有循环都需要移除,如果向量化代码过于晦涩且数据规模不大,可保留循环保证可读性;但针对大规模数据集,向量化带来的性能提升是决定性的。

内容的提问来源于stack exchange,提问作者lambda07

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 17:47:02