- 机器学习
- 深度学习
- AutoML
- 大数据
- 后端
【免费下载链接】h2o-3
H2O is an Open Source, Distributed, Fast & Scalable Machine Learning Platform: Deep Learning, Gradient Boosting (GBM) & XGBoost, Random Forest, Generalized Linear Modeling (GLM with Elastic Net), K-Means, PCA, Generalized Additive Models (GAM), RuleFit, Support Vector Machine (SVM), Stacked Ensembles, Automatic Machine Learning (AutoML), etc.
导读
本文围绕 H2O-3 分布式机器学习平台(当前仓库h2o-3)中 GBM、DRF、Uplift DRF 三类树模型的sample_rate_per_class参数展开,介绍其在不平衡分类数据上的按类别分层采样机制、取值与校验规则、与全局sample_rate的优先级关系,并结合源码与单元测试剖析其底层实现,最终给出 R 与 Python 双语言的可运行实战示例与超参调优建议。阅读完本文,你将掌握如何对多数类降采样、对少数类按需调整采样比例,以改善不平衡数据下的分类模型表现。
参数概览
| 属性 | 说明 |
|---|---|
| 可用算法 | GBM、DRF、Uplift DRF |
| 是否超参数 | 是(可参与网格搜索) |
| 默认值 | 未指定时为null(此时回退到全局sample_rate) |
| 取值范围 | 文档声明为 0.0~1.0;源码实际校验要求每个值落在开区间(0, 1],即严格大于 0 且小于等于 1 |
| 数据类型 | 浮点数数组,长度必须等于响应变量的类别数 |
该参数的官方定义位于 sample_rate_per_class.rst:当训练数据类别严重不平衡时,此选项要求集成中每棵树都从完整训练数据集中按每个类别各自的采样率进行无放回抽样,而不是像sample_rate那样使用一个全局采样因子。
核心机制:按类别分层采样
与全局sample_rate的关系
- 当
sample_rate_per_class被显式指定时,sample_rate将被忽略(该约束同时写在官方文档与本仓库源码中)。 - 若不指定
sample_rate_per_class,树模型退回到sample_rate全局行采样;在 SharedTreeModel.java 中可以看到基类默认_sample_rate = 0.632(DRF 即此默认值),而 GBM 在具体实现中默认值为 1,同时useRowSampling()判定只要_sample_rate < 1或_sample_rate_per_class != null即启用行采样。
数组语义:每类一个采样率
数组中的第 i 个元素对应响应变量按**字典序排列(lexicographic order)**的第 i 个类别的行采样率。以 CovType 数据集(7 类森林覆盖类型)为例,数组长度必须为 7:
1表示该类 100% 保留;0.4表示该类仅保留 40% 的行;- 通过给少数类更高的比例、给多数类更低的比例,即可实现对多数类降采样、对少数类过采样的类间平衡,同时每一类内部仍然是无放回随机抽样。
源码级工作机制
参数的实际校验发生在 SharedTree.java 的validateRowSampleRate()方法中:
protected void validateRowSampleRate() { if (!(0.0 < _parms._sample_rate && _parms._sample_rate <= 1.0)) error("_sample_rate", "sample_rate should be in interval ]0,1] but it is " + _parms._sample_rate + "."); if (_parms._sample_rate_per_class != null) { warn("_sample_rate", "_sample_rate is ignored if _sample_rate_per_class is specified."); if (_parms._sample_rate_per_class.length != nclasses()) error("_sample_rate_per_class", "_sample_rate_per_class must have " + nclasses() + " values (one per class)."); for (int i=0;i<_parms._sample_rate_per_class.length;++i) { if (!(0.0 < _parms._sample_rate_per_class[i] && _parms._sample_rate_per_class[i] <= 1.0)) error("_sample_rate_per_class", "sample_rate_per_class for class " + response().domain()[i] + " should be in interval ]0,1] but it is " + _parms._sample_rate_per_class[i] + "."); } } }从中可以确认三点实现细节:
- 长度校验:数组长度必须与类别数
nclasses()严格一致,否则直接报错,不会静默截断或补全; - 取值校验:官方文档表述的 0.0~1.0 区间,在代码层面被进一步收紧为
(0, 1],即值为0会触发异常(需注意 0.0 与 1.0 的边界差异); - 优先级警告:指定该参数后,系统会对
sample_rate发出"_sample_rate is ignored if _sample_rate_per_class is specified"的警告,而非报错。
实际抽样逻辑由hex.tree.Sample任务完成,见 Sample.java:
for (int row = 0; row < nids._len; row++) { boolean skip = ys.isNA(row); if (!skip) { double rate = _rate_per_class==null ? _rate : _rate_per_class[(int)ys.at8(row)]; rand.setSeed(_seed + row + nids.start()); //seeding is independent of chunking skip = rand.nextFloat() >= rate; //float is good enough, half as much cost } if (skip) is[row] = _ignoreMarker; // Flag row as being ignored by sampling else if (_useMarker != 0) is[row] = _useMarker; }从源码结构可以推断出该实现的关键特征:
- 对每个类取对应的
_rate_per_class[class],与全局_rate二选一; - 抽样结果只是标记行(
OUT_OF_BAG等 marker)而非真正拷贝数据,分布式框架下按块(chunk)独立处理、行号偏移参与随机种子生成,从而保证抽样确定性与分块无关(即同样的seed在不同节点数下可复现); - 被抽掉的行不参与该棵树的直方图统计与分裂,达到“每棵树数据不同”的随机森林/随机梯度提升效果。
该Sample任务被三个算法分别调用:DRF 见 DRF.java,GBM 见 GBM.java,Uplift DRF 见 UpliftDRF.java。
需要注意的概率影响
在 SharedTree.java 中,训练阶段会输出如下日志:
Sample rates per tree (this affects the distribution of probabilities): sample rate for class '<class-name>' : <rate>这意味着按类采样会改变每棵树的训练类分布,进而影响最终预测概率的分布。这是使用该参数时必须理解的副作用——它不是简单的“数据增强”,而是刻意改变模型看到的类先验。若需要以校正后的概率输出(如校准到原始类分布),可结合校准(calibration)机制使用。
与相关参数的分工
| 参数 | 作用维度 | 与sample_rate_per_class的关系 |
|---|---|---|
sample_rate | 行(x 轴)全局采样 | 被sample_rate_per_class覆盖(忽略并告警) |
col_sample_rate | 列(y 轴)采样,默认 1.0 | 二者可同时启用,互不冲突:一个控制行、一个控制列 |
col_sample_rate_per_tree | 每棵树列采样 | 与col_sample_rate相乘生效,同样可与行采样组合 |
sample_rate官方文档见 sample_rate.rst:其明确指出“对于高度不平衡的分类数据集,基于响应类别的分层行采样有助于提升预测精度,可通过sample_rate_per_class(按字典序为每个响应类别一个比例的数组)配置”。col_sample_rate官方文档见 col_sample_rate.rst:行采样与列采样可同时改善泛化能力,降低验证集与测试集误差。
实践中建议对大型数据集将行、列采样率取 0.7~0.8 区间;而针对类别不平衡场景,则应优先考虑sample_rate_per_class逐类控制。
完整实战示例(CovType 不平衡分类)
以下示例完整继承自官方文档,使用 CovType 数据集(用于识别森林覆盖类型),响应变量共 7 类。示例将 Class 2 降采样到 40%,其余类别保持 100%。
Python 版本
import h2o from h2o.estimators.gbm import H2OGradientBoostingEstimator h2o.init() # 导入 covtype 数据集 covtype = h2o.import_file("https://s3.amazonaws.com/h2o-public-test-data/smalldata/covtype/covtype.20k.data") # 将响应列转换为因子类型 covtype[54] = covtype[54].asfactor() # 设置预测变量名与响应列名 predictors = covtype.columns[0:54] response = 'C55' # 划分训练集与验证集 train, valid = covtype.split_frame(ratios = [.8], seed = 1234) # 查看训练集中每个类别的样本计数 print(train[response].table()) # 使用 sample_rate_per_class: # 对 Class 2 降采样,其余类别保持不变 rate_per_class_list = [1, .4, 1, 1, 1, 1, 1] cov_gbm = H2OGradientBoostingEstimator(sample_rate_per_class = rate_per_class_list, seed = 1234) cov_gbm.train(x = predictors, y = response, training_frame = train, validation_frame = valid) # 打印验证集上的 logloss print('logloss', cov_gbm.logloss(valid = True))R 版本
library(h2o) h2o.init() # 导入 covtype 数据集 covtype <- h2o.importFile("https://s3.amazonaws.com/h2o-public-test-data/smalldata/covtype/covtype.20k.data") # 将响应列转换为因子类型 covtype[, 55] <- as.factor(covtype[, 55]) # 设置预测变量名与响应列名 predictors <- colnames(covtype[1:54]) response <- 'C55' # 划分训练集与验证集 covtype_splits <- h2o.splitFrame(data = covtype, ratios = 0.8, seed = 1234) train <- covtype_splits[[1]] valid <- covtype_splits[[2]] # 查看训练集中每个类别的样本计数 h2o.table(train[response]) # 使用 sample_rate_per_class: # 对 Class 2 降采样,其余类别保持不变 rate_per_class_list <- c(1, 0.4, 1, 1, 1, 1, 1) cov_gbm <- h2o.gbm(x = predictors, y = response, training_frame = train, validation_frame = valid, sample_rate_per_class = rate_per_class_list, seed = 1234) # 打印验证集上的 logloss print(h2o.logloss(cov_gbm, valid = TRUE))示例关键点拆解:
- 训练前先用
train[response].table()(Python)或h2o.table(train[response])(R)确认各类别分布,从而针对性设计采样率数组; - 数组下标与类别按字典序一一对应;示例中把相对过大的 Class 2 采样率降至 0.4,实现对该类的随机降采样;
- 使用
seed = 1234保证划分、采样与建模可复现; - 结果指标采用
logloss(多分类对数损失),训练完成后在验证集上评估。
超参数搜索与调优建议
由于sample_rate_per_class标记为“Hyperparameter: yes”,它可以直接放入网格搜索的超参空间中。注意其取值本身是一个数组,网格搜索时应对应传入数组类型的候选值。调优时建议:
- 先统计类别分布:观察少数类与多数类的比例,将采样率数组的初值设为少数类保留 1.0、多数类按比例下调(如 0.3~0.8);
- 与全局采样错开使用:只要设置了
sample_rate_per_class,sample_rate就会被忽略,因此不要同时设置两者,避免混淆; - 结合
col_sample_rate:行(类间平衡)与列(特征多样性)两个维度的随机性可以叠加,进一步提升泛化; - 配合
balance_classes取舍:仓库源码中还存在独立的balance_classes(类平衡过采样)机制(见 SharedTree.java),它基于class_sampling_factors与max_after_balance_size在训练帧层面做分层重采样,而sample_rate_per_class是在每棵树构建层面控制行抽样;两者作用层面不同,可根据是否需要对整帧重采样来分别选择。
源码与测试佐证
- 参数定义:SharedTreeModel.java 中
public double[] _sample_rate_per_class; //fraction of rows to sample for each tree, per class,且useRowSampling()将它与sample_rate一起纳入行采样开关。 - Schema 暴露:
sample_rate_per_class在 REST/Schema 层出现于 SharedTreeV3.java,并分别被 GBM(GBMV3.java)、DRF(DRFV3.java)、Uplift DRF(UpliftDRFV3.java)纳入算法参数列表,印证了文档所述的三种可用算法。 - 单元测试:
- GBM 的
sampleRatePerClass()测试见 GBMTest.java,它使用 CovType 数据,设置parms._sample_rate_per_class = new double[]{0.1f, 0.1f, 0.2f, 0.4f, 1f, 0.3f, 0.2f}(7 类各一个采样率),并以learn_rate=0.05、ntrees=10、max_depth=5完成一次完整训练,可作为该参数在真实数据上被正确消费的回归验证; - DRF 侧同样存在按类采样率的测试配置(见 DRFTest.java),说明 DRF 对该参数的支持不是文档层面的“纸面能力”,而是有实际训练路径覆盖的实现事实。
- GBM 的
常见误区与注意事项汇总
- 数组长度错误会直接报错:
_sample_rate_per_class must have N values (one per class),N 为响应变量类别数,不是特征数; - 值为 0 不合法:源码校验区间为
(0, 1],想“完全剔除某类”应改用更小的正数,或考虑其他类平衡手段; sample_rate会被忽略但仅告警:日志出现 “_sample_rate is ignored if _sample_rate_per_class is specified” 属于预期行为,不是错误;- 类顺序按字典序:数组元素必须与
train[response].table()中显示的类别字典序一致,顺序错位会导致采样“张冠李戴”; - 影响概率分布:按类采样改变了每棵树的训练类分布,最终预测概率会随之偏移,必要时结合模型校准修正;
- 可复现性依赖
seed:抽样采用与行号相关的确定性随机种子,设置固定seed才能跨运行复现同样的抽样结果。
结语
sample_rate_per_class是 H2O-3 树模型中处理不平衡分类数据最细粒度的行采样控制手段:它把全局的sample_rate拆解为逐类的采样率数组,在保持无放回随机抽样的同时,让数据科学家可以精确调节每个类别在每棵树中的“曝光度”。本文给出的参数校验源码、Sample抽样实现、CovType 双语言示例及 GBM/DRF 单元测试路径,共同构成了从“如何用”到“为什么这样实现”的完整闭环,可作为后续调参与阅读 GBM、DRF、Uplift DRF 源码的入口。
- 机器学习
- 深度学习
- AutoML
- 大数据
- 后端
【免费下载链接】h2o-3
H2O is an Open Source, Distributed, Fast & Scalable Machine Learning Platform: Deep Learning, Gradient Boosting (GBM) & XGBoost, Random Forest, Generalized Linear Modeling (GLM with Elastic Net), K-Means, PCA, Generalized Additive Models (GAM), RuleFit, Support Vector Machine (SVM), Stacked Ensembles, Automatic Machine Learning (AutoML), etc.
相关推荐
H2O 中 sample_rate 行采样率参数详解:GBM、DRF、XGBoost 与 Isolation Forest 的默认值、源码校验与调参实战
H2O 中 sample_rate 行采样率参数详解:GBM、DRF、XGBoost 与 Isolation Forest 的默认值、源码校验与调参实战 sam
机器学习深度学习AutoML大数据后端终极NLP教程:如何在100行代码内掌握自然语言处理核心技术?
终极NLP教程:如何在100行代码内掌握自然语言处理核心技术? 想要快速掌握自然语言处理的核心技术却不知从何开始?nlp tutorial项目为你提供了一套完整
示例工程Seed-VC:零样本语音转换的技术架构与工程实践
Seed VC:零样本语音转换的技术架构与工程实践 语音克隆的技术挑战与算法突破 在语音合成领域,零样本语音转换长期面临三大技术障碍:声纹特征提取的精确度不足、
人工智能语音音频
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考