- 机器学习
- 深度学习
- 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 开源机器学习平台(h2o-3)中GET /3/Frames/{key}/columns/{column}/summary这一 REST 端点展开,讲解如何通过一条 HTTP 请求获取数据框(Frame)中某一列的分位数、最小值、最大值、均值、标准差等汇总统计指标。文中将完整解析该端点的参数定义、典型请求路径与 JSON 响应字段含义,并结合 h2o-3 仓库中的 FramesHandler.java、FrameV3.java、Vec.java 等源码,说明摘要数据背后的分布式统计计算机制。读完本文,你将能够直接构造并调用该端点完成单列数据画像,并理解响应中每个字段的真实含义。
端点概览:从 REST 路由到源码实现
GET /3/Frames/{key}/columns/{column}/summary是 H2O REST API 中面向 Frame 的一组端点之一,其功能定义为:返回某列(column)的摘要统计指标,例如最小值、最大值、均值、标准差(sigma)与各百分位数等。
在源码层面,该路由在 RegisterV3Api.java 中注册,注册内容为:
GET /3/Frames/{frame_id}/columns/{column}/summary -> FramesHandler.columnSummary "Return the summary metrics for a column, e.g. min, max, mean, sigma, percentiles, etc."端点注释与对应处理逻辑同时出现在 FramesHandler.java 的类文档中。在 RequestServer.java 里,该路径也被列为/3/Frames/前缀下的合法路由之一。
实际处理函数columnSummary()位于 FramesHandler.java,核心步骤只有三步:
- 通过
getFromDKV("key", s.frame_id.key())从分布式键值存储(DKV)中取出目标 Frame; - 调用
frame.vec(s.column)定位到指定列对应的Vec,若列不存在则抛出H2OColumnNotFoundArgumentException; - 调用
vec.bins()强制触发该列第二轮 rollup(汇总)统计——即直方图与分位数的计算,随后将结果封装为一个单列FrameV3返回。
值得强调的是:摘要数据体积较大,H2O 默认不会在普通拉取 Frame 时计算。在fetch()与fetchLight()的实现中,都有clearBinsField()调用专门将直方图字段置空(见 FramesHandler.java),源码注释明确写道:"Summary data is big, and not always there... You have to call columnSummary to force computation of the summary data."(摘要数据很大且不一定存在,必须调用 columnSummary 强制计算摘要数据。)
请求参数详解
该端点接收两个路径参数,定义如下:
| name | type | description |
|---|---|---|
| key | Frame | 感兴趣的 Frame(数据框),以 FrameSchema 表示 |
| column | string | 感兴趣的列名 |
- key:目标 Frame 在 H2O 分布式 K/V 存储中的键名。构造请求时直接使用 Frame 的标识符(如
allyears2k_headers.hex)即可,H2O 会通过FramesHandler.getFromDKV()校验键是否存在、对象类型是否为 Frame,若键不存在抛出H2OKeyNotFoundArgumentException,类型不匹配则抛出H2OKeyWrongTypeArgumentException(见 FramesHandler.java)。 - column:目标列的名称,对应 Frame 的列名。若该列不存在,处理函数会抛出
H2OColumnNotFoundArgumentException("column", frameId, column)(见 FramesHandler.java)。
从源码结构看,该端点一次只处理一个列;若要查看整个 Frame 所有列的分布概况,可以使用同族的GET /3/Frames/{frame_id}/summary(对应FramesHandler.summary(),会为每个 Vec 发起startRollupStats(fs, Vec.DO_HISTOGRAMS)强制计算含直方图在内的完整 rollup 统计,见 FramesHandler.java)。此外,同族端点还包括获取列域的GET /3/Frames/{frame_id}/columns/{column}/domain(columnDomain())与获取单列数据的GET /3/Frames/{frame_id}/columns/{column}(column()),它们在 FramesHandler.java 中实现,可用于组合完成单列的完整画像。
示例 URI 与请求构造
文档给出的典型请求路径为:
http://127.0.0.1:54321/3/Frames.json/allyears2k_headers.hex/columns/Year/summary其中各段含义如下:
127.0.0.1:54321:本地 H2O 集群节点的默认地址与端口(H2O 默认端口为 54321,可用-port启动参数修改);/3/:REST API 版本号(Schema v3);Frames.json:资源名加上json后缀,指示返回 JSON 格式;allyears2k_headers.hex:Frame 键(key),对应参数表中的key;columns/Year/summary:固定子路径,Year即参数表中的column。
这是标准的 HTTP GET 请求,用curl即可直接调用,例如:
curl "http://127.0.0.1:54321/3/Frames.json/allyears2k_headers.hex/columns/Year/summary"返回体为 JSON 对象(顶层字段frames数组内含单个 Frame 描述)。所有以/3/Frames/开头的路由都会先在 RequestServer.java 中做路径模式匹配,再分发到对应的 Handler 方法执行。
响应结构逐字段解析
端点返回的 JSON 样例(节选关键结构)如下:
{ "frames": [ { "key": null, "off": 0, "len": 100, "checksum": 722728, "rows": 43978, "byteSize": 44058, "isText": false, "default_pctiles": [0.01, 0.1, 0.25, 0.3333333333333333, 0.5, 0.6666666666666666, 0.75, 0.9, 0.99], "columns": [ { "label": "Year", "missing": 0, "zeros": 0, "pinfs": 0, "ninfs": 0, "mins": [1987, 1987, 1987, 1987, 1987], "maxs": [2008, 2008, 2008, 2008, 2008], "mean": 1997.5, "sigma": 6.34436090171059, "type": "int", "domain": null, "data": [1987, 1987, ...], "str_data": null, "precision": 0, "bins": [1999, 1999, ...], "base": 1987, "stride": 1, "pctiles": [1987.2196098049023, 1989.1995997999, 1992.4997498749374, 1994.3331665832916, 1998, 2001.6663331665834, 2003.4997498749374, 2006.799899949975, 2008.7798899449724] } ], "compatible_models": null } ], "compatible_models": null }顶层与 Frame 级字段
- frames:数组,本次查询仅含一个元素,对应目标 Frame 的摘要视图。
- key:Frame 键名(此处在输出中被置空)。
- off / len:数据返回的行偏移与行数,控制从 Frame 中读取
data字段的窗口(此处返回前 100 行样本数据)。 - checksum:Frame 的校验和,用于一致性判断。
- rows:Frame 的总行数(示例中为 43978,对应 airlines 数据集中 Year 列的有效记录数)。
- byteSize:Frame 的近似字节大小。
- isText:是否为文本型 Frame。
- default_pctiles:H2O 默认计算的分位数组,共 9 个分位点:1%、10%、25%、33.33%、50%、66.67%、75%、90%、99%。
- compatible_models:可兼容该 Frame 的模型列表(当前为空)。
列级字段(columns[0])
列级字段在源码中由 FrameV3.ColV3 定义,逐一说明如下:
| 字段 | 含义 | 说明 |
|---|---|---|
| label | 列名 | 即请求中的 column 参数(示例为 "Year") |
| missing | 缺失值(NA)数量 | 对应vec.naCnt() |
| zeros | 零值数量 | 由vec.length() - vec.nzCnt() - missing_count计算得到(见 FrameV3.java) |
| pinfs / ninfs | 正无穷 / 负无穷数量 | 对应vec.pinfs()与vec.ninfs() |
| mins / maxs | 最小 / 最大值数组 | 各含 5 个元素的窗口数组(见下节"极值窗口"说明),对应vec.mins()与vec.maxs() |
| mean | 均值 | 对应vec.mean() |
| sigma | 标准差 | 对应vec.sigma(),对非 NA 值计算sqrt(sum((X-mean(X))^2)) |
| type | 数据类型 | 枚举值:enum、string、int、real、time、uuid(见 FrameV3.java) |
| domain | 列域(类别取值) | 仅分类列(enum)非 null,对应vec.domain() |
| data | 数值型样本数据 | 按off/len窗口截取的实际行数据,字符串与 UUID 列则走str_data |
| str_data | 字符串型样本数据 | 仅 string / uuid 列非 null |
| precision | 小数精度 | -1 表示保留全部位数,来自 chunk 的 precision |
| bins | 直方图 bin 计数 | 仅在摘要端点被强制计算后才有值(见 FrameV3.java) |
| base | 直方图第 0 个 bin 的起点 | 对应vec.base() |
| stride | 每个 bin 的宽度 | 对应vec.stride() |
| pctiles | 分位数实际值 | 与default_pctiles一一对应,对应vec.pctiles() |
极值窗口:为什么 mins/maxs 各含 5 个值?
响应中mins与maxs都是长度为 5 的数组。从 RollupStats.java 的源码可见,每个 Vec 的 rollup 结构固定维护 5 个最小值槽位与 5 个最大值槽位:
_mins = new double[5]; _maxs = new double[5]; Arrays.fill(_mins, Double.MAX_VALUE); Arrays.fill(_maxs,-Double.MAX_VALUE);其作用是从分布式集群各节点(chunk)汇总时保留"每节点最小/最大"的 Top-5 缓冲:各 chunk 先把自身最小值/最大值插入这 5 个槽位(见RollupStats中的min(d)/max(d)逻辑,新值比槽位值小/大时依次"挤掉"并下推),最后在 postGlobal 阶段两两合并。因此当列全为常量(如示例中的 Year 1987~2008 区间,同值 1987 出现多次)时,数组会呈现多个相同值。对绝大多数场景,读取mins[0]与maxs[0]即为全局最小/最大值,而完整数组可用于更细致的分布诊断。
分位数与直方图:default_pctiles 与 pctiles 的对应
default_pctiles与pctiles是两个一一对应的数组:前者是分位点(百分比),后者是该分位点在当前列上的实际取值。
值得注意的是,示例响应中default_pctiles只有 9 个分位点,而 Vec.java 中定义的完整默认分位数组包含 17 个值:
public static final double PERCENTILES[] = {0.001,0.01,0.1,0.2,0.25,0.3,1.0/3.0,0.4,0.5,0.6,2.0/3.0,0.7,0.75,0.8,0.9,0.99,0.999};即 0.1%、1%、10%、20%、25%、30%、33.33%、40%、50%、60%、66.67%、70%、75%、80%、90%、99%、99.9% 共 17 个分位点。在 RollupStats.java 中,分位数数组正是按Vec.PERCENTILES.length分配的:
_pctiles = new double[Vec.PERCENTILES.length]; Arrays.fill(_pctiles, Double.NaN);pctiles()的取值通过RollupStats.get(this, true)获取(见 Vec.java),要求直方图已被计算——这正解释了columnSummary为何要显式调用vec.bins()强制触发第二轮 rollup。分位数值由直方图 bin 上的插值近似得到(示例中 1998 年恰为中位数 50% 分位点的值),而bins、base、stride三个字段共同描述了这个直方图的形状:base为第 0 个 bin 起点,stride为 bin 宽度。
数据类型的完整取值
type字段的取值由 FrameV3.java 中的类型判定逻辑决定:
type = vec.isUUID() ? "uuid" : vec.isString() ? "string" : vec.isCategorical() ? "enum" : vec.isTime() ? "time" : vec.isInt() ? "int" : "real";对应六种取值:enum(分类)、string(字符串)、int(整数)、real(浮点)、time(时间)、uuid。同时domain仅对enum列非 null,domain_cardinality给出分类列的类别基数(见 FrameV3.java)。
分布式计算原理:两轮 rollup 机制
H2O 是分布式内存计算平台,一个 Vec 的数据按行分片存储在多个节点的 chunk 中。列摘要指标并非单机串行计算,而是通过**两轮 rollup(预汇总)**机制在集群上并行完成:
- 第一轮 rollup(基本统计):各 chunk 在本地汇总
_mean、_sigma(对非 NA 值的均值与方差,见 RollupStats.java)、_mins/_maxs极值窗口、_rows、_naCnt、_nzCnt等,然后逐级归并到全局;合并时对_sigma采用基于delta的可并行合并公式(见 RollupStats.java),保证多节点结果的精度。 - 第二轮 rollup(直方图 + 分位数):通过
vec.bins()/startRollupStats(fs, Vec.DO_HISTOGRAMS)触发(见 Vec.java 与 FramesHandler.java),各 chunk 计算局部直方图后合并为全局直方图,再基于全局 bin 分布插值出pctiles。
因此,GET /3/Frames/{key}/columns/{column}/summary实际做了两件事:一是取出并返回已缓存的、来自第一轮 rollup 的均值/极值等基础指标;二是显式强制计算第二轮的直方图与分位数,然后封装成单列 Frame 返回。这也是为什么该端点的注释将其功能概括为 "Return the summary metrics for a column, e.g. mins, maxes, mean, sigma, percentiles, etc."(返回某列的摘要指标,如最小值、最大值、均值、标准差、百分位数等)。
客户端调用方式:Python 与 R
除了直接用 HTTP 请求,H2O 官方客户端也提供了等价能力:
- Python 客户端:
H2OFrame.summary()目前已被标记为 Deprecated,官方推荐改用get_summary()(以字典形式返回摘要统计)或show_summary()(直接美化打印),相关说明见 h2o-py/h2o/frame.py。此外frame.describe(chunk_summary=True)可输出每列的完整描述信息(见 frame.py)。 - R 客户端:
h2o-package/R/目录中提供了对应的描述与摘要函数,可直接调用h2o.describe()系列接口完成类似分析。
在 Flow(H2O 自带的 Web UI)中,点击列的 Summary 标签页时,底层同样调用的是本端点。
典型应用场景
- 数据质量探查:通过
missing、zeros、pinfs/ninfs快速发现缺失值、零值、无穷值异常,决定清洗策略; - 特征分布画像:通过
mean/sigma与pctiles判断特征偏态、离群点与取值范围,为标准化或分箱做依据; - 类型识别:通过
type、domain、domain_cardinality确认列的分类/数值属性,决定建模时的编码方式; - 直方图可视化:利用
bins、base、stride直接重建列直方图,无需额外扫描数据。
注意事项与限制
- 摘要计算有成本:
columnSummary会强制触发直方图计算,首次调用可能触发全列扫描;对超大列(数十亿行)建议在非关键路径使用,并注意响应中data/bins字段的体积。 - 默认仅 9 个分位点返回:示例输出中的
default_pctiles仅列出 9 个常用分位点,而底层Vec.PERCENTILES实际维护 17 个分位点;按需在客户端读取完整数组时,应以Vec.PERCENTILES与pctiles的长度对齐为准。 - 列名大小写敏感:
column参数需与 Frame 列名完全一致,否则抛出H2OColumnNotFoundArgumentException。 - data 字段为样本窗口:
off/len控制返回的行窗口,并非全列数据,超大列的分析请依赖统计指标而非原始样本。
深入阅读
若想继续深挖实现细节,可重点阅读以下源码文件:
- h2o-core/src/main/java/water/api/FramesHandler.java:
columnSummary、summary、column、columnDomain等端点实现与路由注释; - h2o-core/src/main/java/water/api/schemas3/FrameV3.java:
FrameV3与ColV3的字段定义、类型判定与直方图字段的惰性计算策略; - h2o-core/src/main/java/water/fvec/Vec.java:
PERCENTILES默认分位数组、bins()/pctiles()/startRollupStats()等 Vec 统计入口; - h2o-core/src/main/java/water/fvec/RollupStats.java:rollup 统计的两轮计算、极值窗口与分位数合并的底层实现;
- h2o-core/src/main/java/water/api/RegisterV3Api.java:
/3/Frames/家族端点的路由注册表。
- 机器学习
- 深度学习
- 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 REST API 实战指南:从版本约定到 GBM 端到端调用
H2O 3 REST API 实战指南:从版本约定到 GBM 端到端调用 H2O 3 的所有客户端能力——包括 Flow Web UI、R 与 Python 绑
机器学习深度学习AutoML大数据后端cAdvisor v2.0 Remote REST API 完全指南:stats / summary / spec 端点详解与源码级解析
cAdvisor v2.0 Remote REST API 完全指南:stats / summary / spec 端点详解与源码级解析 cAdvisor(Co
可观测性指标监控云原生AWX Group 潜在子组列表 API 实战解析:potential_children 端点原理与调用指南
AWX Group 潜在子组列表 API 实战解析:potential_children 端点原理与调用指南 导读 在 AWX(Red Hat Ansible
后端运维任务调度
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考