跳转到内容

分析流程

每次 Marivo 分析都从一个 指标 开始,并按写-运行-读循环推进:智能体写出一个 意图(一次操作调用及其参数),运行它,读取类型化结果,再决定下一步。

各组成部分:

  • 会话 持有指导问题、语义目录,以及每一步的持久化结果。
  • 操作调用 是一次确定性的分析步骤 —— observecompareattributediscover.<objective> 以及其他核心操作 —— 及其参数。这些参数就是分析规格。
  • 产物 是操作的类型化结果。产物是步骤之间的边界:每个操作消费 特定产物家族,并产出另一个。
import marivo.analysis as mv
import marivo.semantic as ms
session = mv.session.get_or_create(name="revenue-investigation", question="Why did Q4 drop?")
catalog = session.catalog
revenue = catalog.get("metric.sales.revenue") # a metric object
region = catalog.get("dimension.sales.orders.region") # a dimension object

get_or_create 是幂等的:它会附着到同名的已有会话,或创建一个新会话,并设为当前 会话。 会话的精简 API 为 get_or_createcurrent()list()delete(name)

操作接受目录对象和若干共享的值对象。多数意图都会复用这些输入:

形态含义
指标输入catalog.get("metric.sales.revenue")语义-id 字符串、目录指标对象或 MetricRef。来自 ms.aggregate(...) 的编写引用也可用;仅引用约束适用于语义编写参数,不适用于分析消费输入。
维度输入catalog.get("dimension.sales.orders.region")语义-id 字符串、目录维度对象,或其 DimensionRef / TimeDimensionRef(见 语义引用)。用于 dimensionsslice_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}}聚合前的行过滤(见下方运算符)。
AlignmentPolicymv.window_bucket()compare / correlate 时两个窗口如何配对。

结果的 语义类型graindimensions 决定:scalar(两者都没有)、 time_series(仅粒度)、segmented(仅维度)或 panel(两者皆有)。

键是目录维度;值为标量(==)、列表(in),或结构化的 {"op": ..., "value": ...} 形式:

形式含义
"US"==(相等)
["US", "CA"]in(成员)
{"op": "!=", "value": "US"}不等
{"op": ">", "value": 100}>=<<= 同理)数值比较
{"op": "between", "value": ["2026-07-01", "2026-09-30"]}闭区间(恰好两个值)

任何分析都从这里开始:在某个时间范围和/或分段上物化一个指标。

参数类型必填默认含义
metric指标对象 / 引用,或非空序列要物化的指标,或同一范围下多个指标的序列(多指标观测)。不支持裸字符串。
time_scopedictNone半开 {"start", "end"} 窗口。
grain粒度None时间桶;存在 ⇒ 时间序列或面板。
dimensionslist[ref]None分段轴。
slice_bydictNone聚合前的行过滤。
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")

量化两个 observe 结果之间的变化(当前减 baseline)。两个 frame 必须共享指标与 语义类型。

参数类型必填默认含义
currentMetricFrame当前期 frame。
baselineMetricFrame基线期 frame。
alignmentAlignmentPolicywindow_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(...)

把差值的变动归因到显式轴上。这是“为什么变了?”分析的默认公共入口。 组件-感知的比率和加权-average 差值会使用混合归因。普通 非线性采样折叠(例如分位数、min、max、首个或 last)不能直接按轴求和; 除非它们属于已持久化组件-感知派生指标差值,否则仍不支持。

参数类型必填默认含义
frameDeltaFrame要归因的差值。
axeslist[dimension]进行归因的分段轴或时间轴。
mode"flat" | "nested" | "recursive""flat"层级展开方式;输出仍然是 AttributionFrame
attribution = session.attribute(delta, axes=[region], mode="flat")
attribution.show()

在对齐后的桶上度量两个指标之间的关联。

参数类型必填默认含义
abMetricFrame要关联的两个 frame。
measure_ameasure_bstrframe 度量各 frame 上的数值列。
alignmentAlignmentPolicywindow_bucket桶配对。
method"pearson""pearson"关联方法(v1:Pearson,零滞后)。

将一个时间序列或面板向前投影。

参数类型必填默认含义
historyMetricFrame(time_series/面板)连续历史,无 NaN。
horizonint要投影的桶数(≥ 1)。
model"naive" | "seasonal_naive" | "drift""seasonal_naive"预测策略。
seasonality_periodint按粒度覆盖季节周期(day=7、week=52、month=12、quarter=4)。
interval_levelfloat0.95预测区间的置信水平。
measure_columnstrframe 度量要预测的列。
history = session.observe(revenue, time_scope={"start": "2026-01-01", "end": "2026-04-01"}, grain="day")
projection = session.forecast(history, horizon=30)

对一个产物运行质量检查,返回一个独立的 QualityReportartifact.quality_summary 只是 cheap、已持久化的元数据投影;它不等同于执行 session.assess_quality(artifact)

参数类型必填默认含义
frameMetricFrame要检查的 frame。

对一个指标在两期之间均值是否变化做配对检验。

参数类型必填默认含义
abMetricFrame当前期与基线期 frame。
hypothesis"mean_changed""mean_changed"检验类型(v1)。
value_avalue_bstrframe 度量各 frame 上的数值列。
alignmentAlignmentPolicywindow_bucket检验的配对方式。
samplingSamplingPolicy推断配对/最小样本规则。
alphafloat0.05显著性水平。

发现 —— session.discover.*CandidateSet

Section titled “发现 —— session.discover.* → CandidateSet”

发现操作在一个产物中搜索确定性候选行,并返回 CandidateSet。候选行顺序 是确定性 score order,不是 Marivo 的推荐。

辅助函数源形状必填关键选项
point_anomaliesMetricFrame time_series/面板valuethreshold=3.0
period_shiftsDeltaFrame time_series/面板≥ 4 个桶valuethreshold=2.0
driver_axesDeltaFramesearch_spacevaluelimit
interesting_slicesMetricFrameDeltaFramesearch_spacevaluethreshold=2.0limit
interesting_windowstime_series/面板 framevaluethreshold=2.0
cross_sectional_outliersMetricFrame segmented/面板peer_scopevaluethreshold=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 家族(MetricFrameMetricFrameDeltaFrameDeltaFrame)的前提下重塑 frame。

变换关键参数效果
filterpredicate(callable)保留谓词为真的行。
sliceslice_by(轴 → 值/列表/区间)保留匹配精确轴值的行。
rollupdrop_axes删除轴并对度量重新聚合。
topkbylimitorder按某个度量取前 N 行(默认 order="decrease")。
bottomkbylimit取后 N 行。
rankbymethodrank_column按某个度量排序并加一列 rank。
normalizemodebaselineindex / share / pct_change / per_unit / z_score(仅 MetricFrame)。
windowwindow限制到一个时间窗口。

累计 MetricFrame 包含锚定到全部历史的累计值。observe 窗口仅裁剪展示行;累计值本身不会被重置。

  • show()contract()transform.window(...) 在累计 frame 上正常工作。
  • correlatediscoverassess_qualityhypothesis_test 允许使用,但解读结果时需注意累计语义。
  • compareattributeforecast 在 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_caveat
windowed = 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_scopegrain 仅标注 frame 的窗口元数据,并通过 ctx 传递给 build。 在 build() 内使用 ctx.bucket(time_expr) 可将时间戳截断到粒度边界。

需要做终端本地 pandas 工作、且不必回到类型化 Marivo 操作时,使用 artifact.to_pandas()

智能体读取产物时按层下钻,以降低跨 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)

每个操作都会把证据写入会话,使结论保持可审计。

  • 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.catalog
revenue = 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由谁产出
MetricFrameobservederive_metric_frame
DeltaFramecompare
AttributionFrameattribute
AssociationResultcorrelate
ForecastFrameforecast
QualityReportassess_quality
HypothesisTestResulthypothesis_test
CandidateSetdiscover.*