分析流程
每次 Marivo 分析都从一个 指标 开始,并按写-运行-读循环推进:智能体写出一个 意图(一次操作调用及其参数),运行它,读取类型化结果,再决定下一步。
各组成部分:
- 会话 持有指导问题、语义目录,以及每一步的持久化结果。
- 操作调用 是一次确定性的分析步骤 ——
observe、compare、attribute、discover.<objective>以及其他核心操作 —— 及其参数。这些参数就是分析规格。 - 产物 是操作的类型化结果。产物是步骤之间的边界:每个操作消费 特定产物家族,并产出另一个。
import marivo.analysis as mvimport marivo.semantic as mssession = mv.session.get_or_create(name="revenue-investigation", question="Why did Q4 drop?")catalog = session.catalogrevenue = catalog.get("metric.sales.revenue") # a metric objectregion = catalog.get("dimension.sales.orders.region") # a dimension objectget_or_create 是幂等的:它会附着到同名的已有会话,或创建一个新会话,并设为当前
会话。
会话的精简 API 为 get_or_create、current()、list() 和 delete(name)。
一个意图如何被指定
Section titled “一个意图如何被指定”操作接受目录对象和若干共享的值对象。多数意图都会复用这些输入:
| 值 | 形态 | 含义 |
|---|---|---|
| 指标输入 | catalog.get("metric.sales.revenue") | 语义-id 字符串、目录指标对象或 MetricRef。来自 ms.aggregate(...) 的编写引用也可用;仅引用约束适用于语义编写参数,不适用于分析消费输入。 |
| 维度输入 | catalog.get("dimension.sales.orders.region") | 语义-id 字符串、目录维度对象,或其 DimensionRef / TimeDimensionRef(见 语义引用)。用于 dimensions、slice_by 的键和 axis。 |
time_scope | {"start": "2026-10-01", "end": "2027-01-01"} | 半开时间区间 —— start 含、end 不含。 |
grain | "day" | "week" | "month" | "quarter" | "year" | "hour" | … | 时间桶大小。存在 ⇒ 时间序列或面板。 |
dimensions | [region, country] | 分段轴。v1 中全部必须解析到指标所属实体。 |
slice_by | {region: "US"} 或 {amount: {"op": ">", "value": 100}} | 聚合前的行过滤(见下方运算符)。 |
AlignmentPolicy | mv.window_bucket() | compare / correlate 时两个窗口如何配对。 |
结果的 语义类型 由 grain 和 dimensions 决定:scalar(两者都没有)、
time_series(仅粒度)、segmented(仅维度)或 panel(两者皆有)。
slice_by 谓词运算符
Section titled “slice_by 谓词运算符”键是目录维度;值为标量(==)、列表(in),或结构化的
{"op": ..., "value": ...} 形式:
| 形式 | 含义 |
|---|---|
"US" | ==(相等) |
["US", "CA"] | in(成员) |
{"op": "!=", "value": "US"} | 不等 |
{"op": ">", "value": 100}(>=、<、<= 同理) | 数值比较 |
{"op": "between", "value": ["2026-07-01", "2026-09-30"]} | 闭区间(恰好两个值) |
observe → MetricFrame
Section titled “observe → MetricFrame”任何分析都从这里开始:在某个时间范围和/或分段上物化一个指标。
| 参数 | 类型 | 必填 | 默认 | 含义 |
|---|---|---|---|---|
metric | 指标对象 / 引用,或非空序列 | 是 | — | 要物化的指标,或同一范围下多个指标的序列(多指标观测)。不支持裸字符串。 |
time_scope | dict | 否 | None | 半开 {"start", "end"} 窗口。 |
grain | 粒度 | 否 | None | 时间桶;存在 ⇒ 时间序列或面板。 |
dimensions | list[ref] | 否 | None | 分段轴。 |
slice_by | dict | 否 | None | 聚合前的行过滤。 |
time_dimension | 引用 | 否 | 实体默认 | 当实体声明多个时间轴时选择其一。 |
expect_shape | 形状 | 否 | None | 守卫;若预测形状不符,在访问后端前抛错。 |
current = session.observe( revenue, time_scope={"start": "2026-10-01", "end": "2027-01-01"}, grain="month", dimensions=[region],)传入序列即可在一个 frame 中观测多个相同-范围指标。Marivo 会把同一
数据源的指标合并为一次查询,跨数据源的指标按时间轴
outer-连接。用 frame.metric(id) 投影出 arity-1 frame,对单个指标做
drill-down。
report = session.observe( [revenue, catalog.get("metric.sales.total_orders")], time_scope={"start": "2026-10-01", "end": "2027-01-01"}, grain="month",)revenue_only = report.metric("sales.revenue")compare → DeltaFrame
Section titled “compare → DeltaFrame”量化两个 observe 结果之间的变化(当前减 baseline)。两个 frame 必须共享指标与
语义类型。
| 参数 | 类型 | 必填 | 默认 | 含义 |
|---|---|---|---|---|
current | MetricFrame | 是 | — | 当前期 frame。 |
baseline | MetricFrame | 是 | — | 基线期 frame。 |
alignment | AlignmentPolicy | 否 | window_bucket | 桶/分段如何配对。 |
baseline = session.observe( revenue, time_scope={"start": "2025-10-01", "end": "2026-01-01"}, grain="month", dimensions=[region],)delta = session.compare(current, baseline)compare 默认用 window_bucket 配对桶。传入 alignment= 可覆盖 ——
mv.dow_aligned()、mv.holiday_aligned() 或 mv.holiday_and_dow_aligned();calendar
支持的几种还接受 calendar=mv.CalendarRef(...)。
attribute → AttributionFrame
Section titled “attribute → AttributionFrame”把差值的变动归因到显式轴上。这是“为什么变了?”分析的默认公共入口。 组件-感知的比率和加权-average 差值会使用混合归因。普通 非线性采样折叠(例如分位数、min、max、首个或 last)不能直接按轴求和; 除非它们属于已持久化组件-感知派生指标差值,否则仍不支持。
| 参数 | 类型 | 必填 | 默认 | 含义 |
|---|---|---|---|---|
frame | DeltaFrame | 是 | — | 要归因的差值。 |
axes | list[dimension] | 是 | — | 进行归因的分段轴或时间轴。 |
mode | "flat" | "nested" | "recursive" | 否 | "flat" | 层级展开方式;输出仍然是 AttributionFrame。 |
attribution = session.attribute(delta, axes=[region], mode="flat")attribution.show()correlate → AssociationResult
Section titled “correlate → AssociationResult”在对齐后的桶上度量两个指标之间的关联。
| 参数 | 类型 | 必填 | 默认 | 含义 |
|---|---|---|---|---|
a、b | MetricFrame | 是 | — | 要关联的两个 frame。 |
measure_a、measure_b | str | 否 | frame 度量 | 各 frame 上的数值列。 |
alignment | AlignmentPolicy | 否 | window_bucket | 桶配对。 |
method | "pearson" | 否 | "pearson" | 关联方法(v1:Pearson,零滞后)。 |
forecast → ForecastFrame
Section titled “forecast → ForecastFrame”将一个时间序列或面板向前投影。
| 参数 | 类型 | 必填 | 默认 | 含义 |
|---|---|---|---|---|
history | MetricFrame(time_series/面板) | 是 | — | 连续历史,无 NaN。 |
horizon | int | 是 | — | 要投影的桶数(≥ 1)。 |
model | "naive" | "seasonal_naive" | "drift" | 否 | "seasonal_naive" | 预测策略。 |
seasonality_period | int | 否 | 按粒度 | 覆盖季节周期(day=7、week=52、month=12、quarter=4)。 |
interval_level | float | 否 | 0.95 | 预测区间的置信水平。 |
measure_column | str | 否 | frame 度量 | 要预测的列。 |
history = session.observe(revenue, time_scope={"start": "2026-01-01", "end": "2026-04-01"}, grain="day")projection = session.forecast(history, horizon=30)assess_quality → QualityReport
Section titled “assess_quality → QualityReport”对一个产物运行质量检查,返回一个独立的 QualityReport。
artifact.quality_summary 只是 cheap、已持久化的元数据投影;它不等同于执行
session.assess_quality(artifact)。
| 参数 | 类型 | 必填 | 默认 | 含义 |
|---|---|---|---|---|
frame | MetricFrame | 是 | — | 要检查的 frame。 |
hypothesis_test → HypothesisTestResult
Section titled “hypothesis_test → HypothesisTestResult”对一个指标在两期之间均值是否变化做配对检验。
| 参数 | 类型 | 必填 | 默认 | 含义 |
|---|---|---|---|---|
a、b | MetricFrame | 是 | — | 当前期与基线期 frame。 |
hypothesis | "mean_changed" | 否 | "mean_changed" | 检验类型(v1)。 |
value_a、value_b | str | 否 | frame 度量 | 各 frame 上的数值列。 |
alignment | AlignmentPolicy | 否 | window_bucket | 检验的配对方式。 |
sampling | SamplingPolicy | 否 | 推断 | 配对/最小样本规则。 |
alpha | float | 否 | 0.05 | 显著性水平。 |
发现 —— session.discover.* → CandidateSet
Section titled “发现 —— session.discover.* → CandidateSet”发现操作在一个产物中搜索确定性候选行,并返回 CandidateSet。候选行顺序
是确定性 score order,不是 Marivo 的推荐。
| 辅助函数 | 源形状 | 必填 | 关键选项 |
|---|---|---|---|
point_anomalies | MetricFrame time_series/面板 | — | value、threshold=3.0 |
period_shifts | DeltaFrame time_series/面板 | ≥ 4 个桶 | value、threshold=2.0 |
driver_axes | DeltaFrame | search_space | value、limit |
interesting_slices | MetricFrame 或 DeltaFrame | — | search_space、value、threshold=2.0、limit |
interesting_windows | time_series/面板 frame | — | value、threshold=2.0 |
cross_sectional_outliers | MetricFrame segmented/面板 | — | peer_scope、value、threshold=3.0 |
series = session.observe(revenue, time_scope={"start": "2026-01-01", "end": "2026-04-01"}, grain="day")candidates = session.discover.point_anomalies(series, threshold=2.0)candidates.show()Advanced 引用 —— session.transform.*
Section titled “Advanced 引用 —— session.transform.*”变换在保持 frame 家族(MetricFrame → MetricFrame,DeltaFrame →
DeltaFrame)的前提下重塑 frame。
| 变换 | 关键参数 | 效果 |
|---|---|---|
filter | predicate(callable) | 保留谓词为真的行。 |
slice | slice_by(轴 → 值/列表/区间) | 保留匹配精确轴值的行。 |
rollup | drop_axes | 删除轴并对度量重新聚合。 |
topk | by、limit、order | 按某个度量取前 N 行(默认 order="decrease")。 |
bottomk | by、limit | 取后 N 行。 |
rank | by、method、rank_column | 按某个度量排序并加一列 rank。 |
normalize | mode、baseline | index / share / pct_change / per_unit / z_score(仅 MetricFrame)。 |
window | window | 限制到一个时间窗口。 |
累计 frame 注意事项
Section titled “累计 frame 注意事项”累计 MetricFrame 包含锚定到全部历史的累计值。observe 窗口仅裁剪展示行;累计值本身不会被重置。
show()、contract()和transform.window(...)在累计 frame 上正常工作。correlate、discover、assess_quality和hypothesis_test允许使用,但解读结果时需注意累计语义。compare、attribute和forecast在 v1 中拒绝累计 frame。请使用基础流量指标 执行这些意图——一个窗口内的累计差值等于该窗口内的基础总量。
cum_frame = session.observe( cumulative_active_users, time_scope={"start": "2026-01-01", "end": "2026-04-01"}, grain="day",)cum_frame.contract() # 显示 running_total_caveatwindowed = session.transform.window(cum_frame, window={"start": "2026-02-01", "end": "2026-03-01"})# 对于 compare/attribute/forecast,请改为 observe base metric:base_frame = session.observe(active_users, ...)受治理的 derive —— session.derive_metric_frame(...)
Section titled “受治理的 derive —— session.derive_metric_frame(...)”当自定义 Ibis 计算结果必须回到类型化指标流程时,使用 derive_metric_frame。它总是返回
MetricFrame。语义引用标识指标、时间和维度绑定;查询输出列是普通字符串。
import marivo.datasource as md
warehouse = md.ref("datasource.warehouse")custom = session.derive_metric_frame( metric=session.catalog.get("metric.sales.revenue"), query=mv.ibis_query( datasource=warehouse, build=lambda db, ctx: db.table("orders"), ), columns=mv.metric_columns( value="value", time=mv.time_column( column="order_date", ref=session.catalog.get("time_dimension.sales.orders.order_date"), ), dimensions=[ mv.dimension_column( column="region", ref=session.catalog.get("dimension.sales.orders.region"), ), ], ), time_scope={"start": "2026-06-18", "end": "2026-06-25"}, grain="day", label="custom_revenue_by_region",)custom.show()与 observe 不同,derive_metric_frame 不会对 build 输出进行过滤或聚合——
time_scope 和 grain 仅标注 frame 的窗口元数据,并通过 ctx 传递给 build。
在 build() 内使用 ctx.bucket(time_expr) 可将时间戳截断到粒度边界。
需要做终端本地 pandas 工作、且不必回到类型化 Marivo 操作时,使用
artifact.to_pandas()。
读取与恢复产物
Section titled “读取与恢复产物”智能体读取产物时按层下钻,以降低跨 loop 成本:
repr(delta) # 廉价单行提示delta.show() # 有界当前状态读取delta.contract() # 机械有效的下一步操作delta.to_pandas() # 终端导出,用于自定义本地分析用 artifact.contract().affordances 查看机械兼容性。它只说明哪些公共操作
在机械上可以消费该产物、缺哪些输入;它不排序、不推荐,也不决定下一步。
后续脚本需要前序结果时,读取持久化事实,而不是重跑上游查询:
summaries = session.frame_summaries()jobs = session.recent_jobs(limit=5)previous = session.get_frame(ref)证据链与知识
Section titled “证据链与知识”每个操作都会把证据写入会话,使结论保持可审计。
session.knowledge()—— 整个会话的观察摘要、既定事实、驱动因素事实、未决异常和建议的后续。session.evidence.findings(...)、.propositions(...)、.assessments(...)、.proposition(id)、.latest_assessment(id)、.trace(id)—— 查找证据对象, 并把一个命题追溯回支持它的证据项。
完整模型见 证据链。
import marivo.analysis as mv
session = mv.session.get_or_create(name="revenue-check", question="Why did Q4 drop?")catalog = session.catalogrevenue = catalog.get("metric.sales.revenue")region = catalog.get("dimension.sales.orders.region")
current = session.observe( revenue, time_scope={"start": "2026-10-01", "end": "2027-01-01"}, grain="month", dimensions=[region],)baseline = session.observe( revenue, time_scope={"start": "2025-10-01", "end": "2026-01-01"}, grain="month", dimensions=[region],)delta = session.compare(current, baseline)attribution = session.attribute(delta, axes=[region])attribution.show()拿到 delta 后,可以继续分支:用 session.discover.period_shifts(delta) 找出变化发生在何时,
或用 session.forecast(current, horizon=3) 向前投影。
Frame 类型
Section titled “Frame 类型”| Frame | 由谁产出 |
|---|---|
MetricFrame | observe、derive_metric_frame |
DeltaFrame | compare |
AttributionFrame | attribute |
AssociationResult | correlate |
ForecastFrame | forecast |
QualityReport | assess_quality |
HypothesisTestResult | hypothesis_test |
CandidateSet | discover.* |