logo头像
Snippet 博客主题

广告系统价格指标计算

价格指标计算

本文整理程序化广告里 eCPM、CPM、CPC 的计算口径。仓库当前出价代码只读取计划上的 bid_cpm / max_bid_cpm,没有按计费方式换算;下面的公式来自公开的 DSP 出价与广告报表定义,供后续实现和报表对齐。

金额在公式里用同一币种即可。落到本仓库时,金额字段单位是分,点击率按万分比存储(50 表示 0.5%)。


1. 三个指标分别算什么

指标 全称 回答的问题 计算时机
CPM Cost Per Mille,千次展示成本 每一千次曝光花多少钱 计划出价,或按展示结算后的报表
CPC Cost Per Click,单次点击成本 每一次点击花多少钱 计划出价,或按点击结算后的报表
eCPM effective / expected Cost Per Mille,有效(或预估)千次展示成本 不管原来按 CPM 还是 CPC 卖,折成每一千次曝光值多少钱 竞价前用预估点击率算出价;投放后用真实消耗和曝光回算

ADX 的竞价单位是 CPM。CPC 计划不能直接拿「单次点击价」去和别人的「千次曝光价」比,要先折成 eCPM,再参与排序和回价。


2. 报表口径(投放之后)

报表用真实消耗、曝光、点击,不依赖预估模型。Google Ad Manager / AdMob 的定义是:收入(或消耗)除以曝光再乘 1000 得到 eCPM,CPC 等于收入(或消耗)除以点击。

记:

  • Cost:该维度下的广告消耗
  • Impressions:曝光次数
  • Clicks:点击次数
1
2
3
4
5
6
7
CTR  = Clicks / Impressions

CPM = Cost / Impressions × 1000

CPC = Cost / Clicks

eCPM = Cost / Impressions × 1000

几点对齐方式:

  • 只按 CPM 结算时,报表 CPM 与 eCPM 相同,都是千次曝光的实际花费。
  • 只按 CPC 结算时,消耗来自点击:Cost = Clicks × 成交 CPC。此时没有单独的「展示单价」,用来和 CPM 计划对比的是 eCPM。
  • 把上面的 CPC、CTR 代回去,CPC 计划的事后 eCPM 可以写成:
1
eCPM = CPC × CTR × 1000
  • 曝光为 0 时不算 CPM / eCPM;点击为 0 时不算 CPC。

例:消耗 90 元,曝光 10,000,点击 90。

  • CTR = 90 / 10000 = 0.9%
  • CPM 或 eCPM = 90 / 10000 × 1000 = 9 元
  • CPC = 90 / 90 = 1 元
  • 用 CPC 回算:1 × 0.009 × 1000 = 9 元,与 eCPM 一致

3. 竞价口径(请求进来时)

竞价时还没有这次曝光的真实点击,用预估点击率 pCTR(predicted CTR,0~1 的小数)代替 CTR。DSP 内部把不同计费方式都折成 eCPM,按 eCPM 从高到低选一条,再把这个价格以 CPM 单位返回给 ADX。

3.1 CPM:出价就是 eCPM

固定 CPM(计划上直接填千次曝光价)时:

1
2
eCPM = CPM
Bid = CPM

目标 CPM(TCPM)会按这条流量的点击率相对计划均值上下浮动,点击率更高的流量出更高的 CPM:

1
Bid = Target_CPM × (pCTR / AVG_CTR)

AVG_CTR 是该计划历史平均点击率。比值需要封顶,避免异常高的 pCTR 把出价打得过高。

3.2 CPC:先折成 eCPM 再出价

广告主填写的是目标点击价 Target_CPC。行业里 DSP 的换算是:

1
2
eCPM = pCTR × Target_CPC × 1000
Bid = eCPM

含义:若每一千次曝光里预期会点 pCTR × 1000 次,每次点击值 Target_CPC,则这一千次曝光的预期成本就是上面的 eCPM。

例:CPC 出价 0.9 元,pCTR = 0.9% = 0.009。

1
eCPM = 0.009 × 0.9 × 1000 = 8.1 元

同一 CPC,pCTR 从 0.9% 降到 0.45%,eCPM 降到 4.05 元,出价跟着下降。CPC 本身不变。

若先用平均点击率得到基准 CPM,再按当前流量相对均值缩放,结果与上式相同:

1
2
3
基准 CPM = Target_CPC × AVG_CTR × 1000
Bid = 基准 CPM × (pCTR / AVG_CTR)
= Target_CPC × pCTR × 1000

3.3 返回给 ADX 之前的约束

内部胜出的 eCPM 还要落在广告位底价和计划上限之间,才作为 bid.price(分/CPM)返回:

1
2
3
Bid > 0
Bid ≥ bidfloor
Bid ≤ max_bid_cpm

底价或上限不满足则这条计划不出价。多条计划同时可投时,按 eCPM 取最高的一条(本仓库当前实现按 priority、weight 排序,尚未按 eCPM 排序)。

更完整的在线调价会在基础 eCPM 上再乘预算节奏、一价拍卖的压价、以及目标成本纠偏:

1
2
3
4
Final_Bid = Base_eCPM × Pacing × Shading × Correction

Correction = Target_CPC / Actual_CPC (CPC 计划)
Correction = Target_CPM / Actual_CPM (CPM 计划)
  • Pacing:预算花得过快则小于 1,花得过慢则大于 1。
  • Shading:一价拍卖里通常取 0.7~0.95,避免按预估价值全额出价。
  • Correction:实际 CPC(或 CPM)高于目标时压价,低于目标时放价。

这三项目前都没有进 dl-rtb,实现第一版时可以先只做第 3.1、3.2 节的基础 eCPM。


4. 和本仓库字段怎么对齐

计划表(campaigns)与 Redis 快照里已有这些字段,单位见 schema.sql:

字段 单位 用在
billing_type CPM / CPC 选择下面哪条公式
bid_cpm 分 / 千次曝光 CPM 计划的出价
max_bid_cpm 分 / 千次曝光 出价上限
target_cpc 分 / 次点击 CPC 计划的目标点击价
default_pctr 万分比,50 = 0.5% 没有实时 pCTR 时的默认点击率

万分比换成公式里的小数:

1
pCTR = default_pctr / 10000

金额保持「分」时,CPC 折 eCPM(整数,向下取整):

1
eCPM_分 = target_cpc × default_pctr / 10

推导:target_cpc × (default_pctr / 10000) × 1000 = target_cpc × default_pctr / 10。

例:target_cpc = 90(0.9 元),default_pctr = 90(0.9%)。

1
eCPM_分 = 90 × 90 / 10 = 810    (8.10 元 / 千次曝光)

建议的出价伪代码(尚未实现,当前 effectiveBidCPM 只在 bid_cpm > 0 时用 bid_cpm,否则用 max_bid_cpm,不看 billing_type):

1
2
3
4
5
6
7
8
9
若 billing_type = CPM:
bid = bid_cpm(bid_cpm 为空或 ≤ 0 时用 max_bid_cpm)
若 billing_type = CPC:
bid = target_cpc × pCTR × 1000
bid = min(bid, max_bid_cpm)
若 bid ≤ 0 或 bid < bidfloor:
不出价
否则:
响应 price = bid // 分/CPM

5. 对照例

场景 输入 计算 结果
CPM 出价 bid_cpm = 300 分 eCPM = CPM 出价 300 分(3 元/千次)
CPC 出价 CPC = 200 分,pCTR = 50(0.5%) 200 × 50 / 10 出价 1000 分(10 元/千次)
CPC 报表 消耗 2000 分,曝光 10000,点击 20 CPC = 2000/20;eCPM = 2000/10000×1000 CPC = 100 分;eCPM = 200 分
同一 CPC 不同点击率 CPC = 100 分;pCTR 1% 与 0.2% 100×0.01×1000 与 100×0.002×1000 eCPM 分别为 1000 分、200 分

参考