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

如何通过GridSearchCV获取KMeans的inertia_值与最优聚类数

KMeans结合GridSearchCV调参问题解答

问题背景

作为机器学习初学者,基于SKLearn内置Iris数据集开展KMeans聚类实验,待解决两个核心问题:

  • 使用GridSearchCV调参时,如何获取KMeans的inertia_值以及最优聚类数
  • GridSearchCV是否适用于KMeans的聚类数调优场景

已验证可运行的手动实现方案

目前两种手动遍历的实现均可正常运行,可通过肘部法得到正确聚类数,但遍历效率偏低:

方法1:单模型直接遍历

X = data.data

# 特征标准化
scaler = StandardScaler()
scaled_X = scaler.fit_transform(X)

inertias = []

for i in range(1,20):
    model = KMeans(n_clusters=i, random_state=42)
    model.fit(scaled_X)
    inertias.append(model.inertia_)
inertias

方法2:Pipeline封装遍历

inertias = []
for i in range(1,20):
    pipe = Pipeline([
        ('sc', StandardScaler()),
        ('kmeans', KMeans(n_clusters=i, random_state=42))
    ], verbose=True)

    pipe.fit(scaled_X)
    inertias.append(pipe.named_steps['kmeans'].inertia_)
inertias

以上两种方法绘制inertia折线图后,均可通过肘部法确定最优聚类数为3,与Iris数据集实际类别数一致。

GridSearchCV实现的异常现象

尝试用GridSearchCV复现上述逻辑时,返回结果完全不符合预期,实现代码如下:

pipe = Pipeline([
    ('sc', StandardScaler()),
    ('kmeans', KMeans(random_state=42))
], verbose=True)

param_grid = {
    'kmeans__n_clusters':range(1,20)
}

grid = GridSearchCV(pipe, param_grid=param_grid, verbose=3)
grid.fit(scaled_X)

# 返回结果异常
grid.best_params_
# {'kmeans__n_clusters': 19}

grid.score(scaled_X)
# -26.379283976769145

存在三个核心问题:

  • grid.best_params_返回的最优n_clusters为19,和肘部法结论完全矛盾
  • grid.score()返回值和手动遍历得到的inertia变化规律不匹配
  • 无法直接通过类似grid.inertia_的属性获取所有参数组合对应的inertia值,也无法直接得到肘部法对应的正确最优聚类数3

问题原因与解决方法

为什么GridSearchCV默认返回n_clusters=19

GridSearchCV的核心选型逻辑是交叉验证下评分最大化。KMeans默认的score()方法返回值为负inertia(即score = -inertia),而inertia的固有特性是:聚类数越多,样本到所属簇心的距离和越小,inertia越低,对应的score就越高。在1-19的参数范围内,聚类数取19时score达到最大值,因此GridSearchCV默认返回19是逻辑必然,不是代码bug。

GridSearchCV是否适合调KMeans聚类数

不适合直接用默认配置调聚类数:

  • 聚类数选择属于无监督场景下的偏差-方差权衡,不存在带标签的验证目标支撑交叉验证打分最大化的选型逻辑
  • 肘部法、轮廓系数法等聚类数选型方法,都是基于聚类结果本身的分布特性判断,和GridSearchCV默认的预测精度导向的交叉验证逻辑不匹配
  • GridSearchCV更适合调优KMeans的init、n_init、max_iter这类不改变聚类数的超参数,硬套它来选聚类数属于舍近求远。

如何通过GridSearchCV获取所有聚类数对应的inertia值

如果一定要用GridSearchCV记录不同k对应的inertia,需要做两个配置修改:一是自定义评分器提取每个训练完成的模型的inertia,二是关闭交叉验证的数据集拆分(inertia是训练集上的统计值,拆分不同折计算的inertia没有可比性),参考代码如下:

import numpy as np

# 定义字典存储每个k对应的inertia
inertia_records = {}
def get_inertia_score(estimator, X):
    k_val = estimator.named_steps['kmeans'].n_clusters
    inertia_val = estimator.named_steps['kmeans'].inertia_
    inertia_records[k_val] = inertia_val
    # 返回负inertia符合GridSearchCV最大化评分的逻辑
    return -inertia_val

pipe = Pipeline([
    ('sc', StandardScaler()),
    ('kmeans', KMeans(random_state=42))
])

param_grid = {
    'kmeans__n_clusters':range(1,20)
}

# cv配置为全量数据训练,不做折拆分
grid = GridSearchCV(
    pipe,
    param_grid=param_grid,
    scoring=get_inertia_score,
    cv=[(np.arange(len(scaled_X)), np.arange(len(scaled_X)))],
    verbose=3
)
grid.fit(scaled_X)

代码运行完成后,inertia_records字典中就存储了1-19每个聚类数对应的inertia值,和手动遍历得到的结果完全一致。

如何得到正确的最优聚类数

拿到所有聚类数对应的inertia后,依然需要通过肘部法、轮廓系数法等无监督聚类选型规则判断最优k,不能直接使用grid.best_params_的返回值——只要评分规则和inertia负相关,GridSearchCV永远会选参数范围内最大的聚类数,这是KMeans目标函数的固有特性,和工具本身无关。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 10:51:31