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

H2ORandomForestEstimator类别平衡实现问题求助

解决H2O随机森林类别平衡的实现问题

嘿,我刚好对H2O的类别平衡这块熟得很,帮你把《Practical Machine Learning with H2O》第107页的鸢尾花示例一步步复现,顺便解决你可能遇到的坑!

1. 先搞定不平衡数据集构建

咱们先把环境搭好,再人工造出不平衡的鸢尾花数据——完全对应书籍里的场景:保留前120行,大幅减少virginica样本数量:

import h2o
from h2o.estimators.random_forest import H2ORandomForestEstimator

# 初始化H2O环境(如果本地没启动会自动拉起)
h2o.init()

# 加载H2O内置的鸢尾花数据集(不用额外下载)
iris = h2o.load_dataset("iris")

# 构建不平衡数据集:取前120行,这样virginica只剩20个,和另外两类的50个形成差距
imbalanced_iris = iris[:120, :]

# 确认类别分布,看看是不是真的不平衡
print("不平衡数据集类别分布:")
print(imbalanced_iris["class"].table())

运行完你会看到setosa和versicolor各50个,virginica只有20个,完美符合书籍里的设定。

2. 拆分训练/测试集

接下来拆分数据集,方便后续对比模型效果:

# 按8:2比例拆分训练集和测试集,固定seed保证可复现
train, test = imbalanced_iris.split_frame(ratios=[0.8], seed=123)

# 指定特征列和目标列
x = train.columns[:-1]  # 所有列除了最后一列class
y = "class"

3. 构建你计划的三个模型

现在逐个构建模型,每个都给你标注细节和可能的坑:

模型1:基础随机森林(无类别平衡)

这是基准模型,不做任何平衡处理,用来对比后续模型的效果:

base_rf = H2ORandomForestEstimator(
    ntrees=100,  # 和书籍默认参数一致
    seed=123
)
base_rf.train(x=x, y=y, training_frame=train)

# 查看测试集表现,重点看virginica类的召回率
base_perf = base_rf.model_performance(test_data=test)
print("\n基础模型测试集混淆矩阵:")
print(base_perf.confusion_matrix())
print("基础模型少数类(virginica)召回率:", base_perf.recall()["iris_virginica"])

这里大概率会看到virginica的召回率很低,因为样本太少,模型天然偏向预测多数类。

模型2:开启balance_classes=True的模型

这是核心的平衡模型,H2O会自动对少数类过采样(或对多数类欠采样)来平衡类别:

balanced_rf = H2ORandomForestEstimator(
    ntrees=100,
    balance_classes=True,  # 关键参数:开启类别平衡
    seed=123
)
balanced_rf.train(x=x, y=y, training_frame=train)

# 评估效果
balanced_perf = balanced_rf.model_performance(test_data=test)
print("\n平衡类别模型测试集混淆矩阵:")
print(balanced_perf.confusion_matrix())
print("平衡模型少数类(virginica)召回率:", balanced_perf.recall()["iris_virginica"])

这里你会发现virginica的召回率明显提升,但要注意:默认的balance_classes=True会把所有类别样本量拉到最多类的数量,少数类样本极小时可能导致过拟合,这时候就需要第三个模型。

模型3:balance_classes=True + 自定义采样参数

咱们可以加上class_sampling_fractions指定每个类的采样比例,或者用max_after_balance_size限制平衡后的总样本量,避免过拟合:

# 先获取训练集的类别标签,方便设置采样比例
train_class_labels = train["class"].table()["class"].as_data_frame()["class"].tolist()

# 自定义采样比例:比如给virginica设2.5倍采样(因为训练集里virginica大概是另外两类的1/3)
sampling_fractions = {
    train_class_labels[0]: 1,    # setosa:保持原样本量
    train_class_labels[1]: 1,    # versicolor:保持原样本量
    train_class_labels[2]: 2.5   # virginica:采样2.5倍
}

balanced_rf_custom = H2ORandomForestEstimator(
    ntrees=100,
    balance_classes=True,
    class_sampling_fractions=sampling_fractions,
    # max_after_balance_size=1.2,  # 可选:限制平衡后总样本量为原训练集的1.2倍,防止过拟合
    seed=123
)
balanced_rf_custom.train(x=x, y=y, training_frame=train)

# 评估效果
custom_perf = balanced_rf_custom.model_performance(test_data=test)
print("\n自定义平衡参数模型测试集混淆矩阵:")
print(custom_perf.confusion_matrix())
print("自定义平衡模型少数类(virginica)召回率:", custom_perf.recall()["iris_virginica"])

常见问题排查

如果你在实现中卡壳,大概率是这几个点:

  • H2O版本问题:尽量用和书籍匹配的H2O版本(比如3.30+),避免参数兼容问题
  • 类别列类型错误:确保class列是枚举(categorical)类型,如果不是,用imbalanced_iris["class"] = imbalanced_iris["class"].asfactor()转换
  • 采样参数写错:class_sampling_fractions的键必须是类别列的实际标签(比如"iris_virginica"),不能用索引,否则会报错
  • 评估指标选不对:不平衡数据集别只看准确率,重点看少数类的召回率和F1分数,这两个指标更能反映平衡效果

对比三个模型的少数类召回率,你就能清晰看到类别平衡带来的提升,完美复现书籍里的示例啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 09:19:35