广告 / NOTEBOOK 课程

24 · 预算pacing、约束与整合误差分析

真实点击分布与独立模拟市场 · 可运行单变量实验

构造机制 / 模拟市场只读 · 已保存的实验

已有输出来自保存的教学实验,并非打开页面时重新执行。 代码和原始输出保持不变;数据与历史注释保留原始语言。

24 · 预算pacing、约束与整合误差分析

第18章保留总览;本章单独深入一个问题。正式200k实验不覆盖,教学训练使用独立共享记录。

先预测:总预算相同,为何投放时段不同?

不加pacing的策略只检查剩余总预算,可能较早花光;均匀pacing进一步约束累计花费≤B×请求进度。它不读取未来点击或true_p,只使用当前请求位置和已花费。后半程流量更有价值是此市场的构造,所以均匀pacing可能有利,也可能在别的市场损失价值。

本章固定seed、价值出价、倍数1和预算60,只切换pacing。用同一潜在市场检查差异,接着验证累计约束,最后把真实点击预测与模拟决策的误差边界连起来。

PYTHON · 01
from pathlib import Path
import sys
ROOT=Path.cwd()
if not (ROOT/'reclab').is_dir(): ROOT=ROOT.parent
sys.path.insert(0,str(ROOT))
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import display
from reclab.ads import latest, load_data, split_groups, NUM, CAT, FEATURES
from reclab.paths import ARTIFACTS
from reclab.probability import evaluate
preview=ARTIFACTS/'notebook-previews';preview.mkdir(parents=True,exist_ok=True)
from reclab.auction import market,simulate
synthetic=market(42)
policies={'unpaced':simulate(synthetic,paced=False),'paced':simulate(synthetic,paced=True)}
display(pd.DataFrame([{'policy':name,**{k:r[k] for k in ['spend','wins','clicks','expected_click_value','expected_advertiser_surplus','budget_ok']}} for name,r in policies.items()]))
print('Input probabilities:',synthetic['estimate'].shape,'budgets:',[60]*3)
Notebook 保存的输出 · 本页未执行
policy spend wins clicks expected_click_value expected_advertiser_surplus budget_ok
0 unpaced 179.950958 1654 193 325.099130 145.148171 True
1 paced 179.352946 2522 181 363.687988 184.335042 True
Input probabilities: (6000, 3) budgets: [60, 60, 60]

约束是逐请求不变量,不是终点检查

仅检查最终花费≤预算,会漏掉先超支再修正等错误。实现中每次成交都验证payment≤bid,每次请求后验证累计花费≤总预算;pacing开启时还验证≤时间释放预算。曲线按20个检查点展示,内部断言实际覆盖全部6000请求。

先预测:unpaced曲线会在哪个时段接近预算上限?看图后解释它与后半程价值构造的关系。

PYTHON · 02
fig,ax=plt.subplots(figsize=(8,3))
for name,r in policies.items():
 t=np.array([x['fraction'] for x in r['trace']]);spend=np.array([x['spend'] for x in r['trace']])
 assert (spend<=60+1e-8).all()
 if name=='paced':assert (spend<=60*t[:,None]+1e-8).all()
 ax.plot(t,spend.sum(axis=1),label=name)
ax.plot([0,1],[0,180],'k--',label='Paced combined ceiling')
ax.set(xlabel='Request fraction',ylabel='Simulated cumulative spend',title='Only pacing changed');ax.legend();fig.tight_layout();fig.savefig(preview/'24_pacing.png',dpi=130);plt.show()
Notebook 保存的输出 · 本页未执行
<Figure size 800x300 with 1 Axes>
Notebook 保存的图表

只改一个变量:更紧的预算

pacing固定开启,预算从60降到30;市场、倍数与策略不变。更低预算不保证点击价值按比例下降,因为资格和竞争路径会改变。每个广告主必须单独满足预算,不能用总花费抵消某个广告主超支。

本格实际重新执行模拟,不读取预先写好的表。练习再将budget设为10,记录丢失曝光、花费与价值,解释为什么这不是模型AUC变化。

PYTHON · 03
budget=30.  # Exercise: change only this value to 10.
tight=simulate(synthetic,budget=budget,paced=True)
display(pd.DataFrame(tight['advertisers']))
assert all(r['spend']<=budget+1e-8 for r in tight['advertisers'])
assert all(max(t['spend'])<=budget*t['fraction']+1e-8 for t in tight['trace'])
print('Tighter budget:',{k:tight[k] for k in ['spend','wins','expected_click_value','budget_ok']})
Notebook 保存的输出 · 本页未执行
spend wins clicks
0 29.842661 508 31
1 29.837349 489 27
2 29.819974 453 28
Tighter budget: {'spend': 89.49998375283522, 'wins': 1450, 'expected_click_value': 173.46772010420707, 'budget_ok': True}

整合误差链:预测分数到资格,再到支付

真实任务告诉我们某个样本分布上模型是否能区分点击、概率是否接近真实频率;它没有竞价者、底价、预算与propensity。模拟任务告诉我们给定这些假设时的资源分配,不是对真实Criteo做off-policy评估。

先预测:把估计概率放大1.5但保持真实概率与潜在点击不变,预算会不会自动违规?约束必须始终有效;价值和成交分配却可能改变。这是明确的模拟预测偏差压力测试,不是对真实CTR的校准估计。

PYTHON · 04
biased={**synthetic,'estimate':np.clip(synthetic['estimate']*1.5,.001,.99)}
bias_run=simulate(biased,paced=True)
assert bias_run['budget_ok']
display(pd.DataFrame([{'prediction':name,**{k:r[k] for k in ['spend','wins','expected_click_value','expected_advertiser_surplus','budget_ok']}} for name,r in [('original',policies['paced']),('overestimated',bias_run)]]))
print('Only synthetic estimated probabilities changed; true probabilities and potential clicks are shared.')
Notebook 保存的输出 · 本页未执行
prediction spend wins expected_click_value expected_advertiser_surplus budget_ok
0 original 179.352946 2522 363.687988 184.335042 True
1 overestimated 179.076553 2366 277.435022 98.358469 True
Only synthetic estimated probabilities changed; true probabilities and potential clicks are shared.

回到同一系统:分层验收与下一步

数据层:真实曝光标签、固定来源、哈希、训练边界;预测层:真实训练、select选型、独立calibration、保留audit负结果;决策层:模拟假设、支付与预算不变量。三个领域共用实验生命周期与工作台,不共享不适用的标签和指标。

下面确认教学运行没有替换正式ads run,再读取其预定分段与校准不确定性。练习写一份失败诊断:哪一项是观测证据,哪一项是假设,下一步需要什么新数据?禁止把NDCG、AUC和模拟收入放成一个可比较排行榜。

PYTHON · 05
from reclab.experiments import catalog
receipt,result=latest()
print('Formal 200k run:',receipt['run_id'])
print('Workshop records:',[(r['run_id'],r['config']['workshop'],r['state']) for r in catalog() if r['domain']=='ads' and r['config'].get('workshop')])
display(pd.DataFrame([{'segment':s['segment'],'n':s['raw']['n'],'CTR':s['raw']['click_rate'],'raw_logloss':s['raw']['logloss'],'sigmoid_logloss':s['sigmoid']['logloss']} for s in result['segments']]))
print(result['paired_sigmoid'])
print('Acceptance: budget invariants passed; real and synthetic claims remain separated; negative model/calibration results retained.')
Notebook 保存的输出 · 本页未执行
Formal 200k run: 20261030T125738-f82b6582
Workshop records: [('20261030T130907-22ac6037', 'linear_features', 'completed'), ('20261030T130911-14b5a3de', 'tree_capacity', 'completed')]
segment n CTR raw_logloss sigmoid_logloss
0 low_numeric_missing 17016 0.036495 0.147043 0.146935
1 high_numeric_missing 12912 0.028733 0.121515 0.121515
2 any_unseen_category 11668 0.035996 0.146929 0.146712
3 all_categories_seen 18260 0.031325 0.129065 0.129103
{'calibrated_minus_raw_logloss': -6.130390957040765e-05, 'iid_row_bootstrap_95': [-0.00016953362229380587, 6.253575759107997e-05], 'replicates': 300, 'limitation': 'conditional on fitted models; repeated/related rows and one shard limit independence and generalization'}
Acceptance: budget invariants passed; real and synthetic claims remain separated; negative model/calibration results retained.

继续阅读原文

本章来源

作者教程英文

张伟楠 / 徐健 · CIKM 2016 RTB教程

领域背景资料;具体复现边界见本章正文。

164页原作者讲义:响应预测、竞价、归因、pacing、定向、底价。Lab机制自编,非完整论文配方复现。

作者论文索引英文

张伟楠 · RTB论文索引

领域背景资料;具体复现边界见本章正文。

用于延伸阅读和追溯论文;索引本身不是讲义。

学习标记可选,仅保存在当前浏览器中。打开页面不会自动标记已学。