DEBUG.WIKI
野草云;香港 200Mbps 峰值;不限月流量 · BGP VPS;查看套餐 →
腾讯云;让你的想法跑起来;轻量服务器 · 建站 / Docker / API;查看产品 →
阿里云;从建站到云上业务;云服务器 · 数据库 · 对象存储;查看产品 →

RandomForest 设置 balanced 后,说字符串类别不在权重里

scikit-learn 1.9 的类别权重字典路径会把数字形式字符串转成整数,导致 RandomForest 的 balanced 权重匹配失败。保留标签语义,核对版本与显式样本权重方案。

标签是字符串 "1"、"2",RandomForestClassifier(class_weight="balanced") 却报 The classes, [1, 2], are not in class_weight。报错把字符串打印成整数,是值得追踪的线索;不要先把标签文件整列改成数字。

scikit-learn 1.9.0 有这项回归,1.9.1 正式源码仍保留相关转换。自动计算的权重字典用原字符串作键,后续字典匹配路径却尝试 int(c),于是用整数去查字符串键。普通整数标签或不能转成整数的 "a"、"b" 不一定触发,所以只用常见测试标签可能漏掉它。

保留原标签,检查实际权重路径

记录真实标签的类型与不同值、分类器的 class_weight、是否已有 sample_weight,以及完整版本。不要只看 CSV 显示出来的内容,"01" 和 "1" 可能是两个不同业务类别,转成整数会把它们合并。

直接调用 compute_class_weight 的字典模式也会经过相关分支。仅把 balanced 换成一个仍以数字字符串为键的字典,未必规避。报错也不表示训练样本真的缺少类别;应先对照 classes、原始 y 和权重字典键的类型。

单输出分类可明确计算样本权重

在只有一个分类输出、原来没有其他样本权重的场景,可以按 balanced 的定义,从原标签计数生成逐样本权重,并让分类器不再重复计算类别权重:

import numpy as np
from sklearn.ensemble import RandomForestClassifier

classes, inverse, counts = np.unique(y, return_inverse=True, return_counts=True)
weights = len(y) / (len(classes) * counts[inverse])
model = RandomForestClassifier(class_weight=None, random_state=0)
model.fit(X, y, sample_weight=weights)

X、y 使用原训练数据;示例没有转换标签。实际树数量、采样与其他超参数仍应保留。这里对应整份训练集的 balanced,与每棵树按 bootstrap 样本重新计算的 balanced_subsample 不是同一规则。

原来还有业务样本权重时,需要明确两类权重是否应相乘及相乘顺序,不能直接覆盖它。多输出分类会涉及每个输出的类别权重组合,也不属于这段单输出示例。交叉验证应在各训练折内计数,不能预先用包含验证数据的标签计算一套权重。

回退与升级都要保留类别身份

若项目允许暂时使用已验证正常的旧依赖,可沿锁文件和环境构建流程回退;不要只在运行中的一台机器改包。升级后先核对数字形式字符串的权重字典匹配,再决定是否恢复分类器自己的 balanced 配置。

验收除拟合完成外,还应确认 classes_ 中保留原字符串、每类权重符合定义,预测输出与下游类别映射一致。覆盖 "01"、"1" 与非数字字符串可以发现隐式转换问题。失败的拟合对象应重新创建;此前用改标签绕过错误生成的模型,也需要按真实标签契约重新评估。