# ECS / ecs_ratio / ARP 计算公式与举例

---

## 一、ECS（Effective Catalog Size）— 有效视频数

### 含义

"今天的曝光分布，**等效于均匀推了多少条视频**。"

### 公式

```
ECS = 2 × Σ(pᵢ × i) − 1
```

其中：
- 把桶内每条视频按**曝光量从多到少排序**，排名记为 `i`（第 1 名、第 2 名 …）
- `pᵢ` = 第 `i` 名视频的曝光量 ÷ 桶内总曝光量（即"曝光占比"）
- 对所有视频求和后乘 2 再减 1

### 值域

- **最小值 = 1**：所有曝光都给了 1 条视频
- **最大值 = N**（N = 桶内去重视频数）：所有视频曝光次数完全相同

### 举例计算

假设某个桶当天有 **5 条视频**被曝光，曝光次数如下：

| 视频 | 曝光次数 | 排名 i（降序）| 占比 pᵢ |
|---|---|---|---|
| A | 600 | 1 | 600/1000 = 0.60 |
| B | 200 | 2 | 200/1000 = 0.20 |
| C | 100 | 3 | 100/1000 = 0.10 |
| D | 60 | 4 | 60/1000 = 0.06 |
| E | 40 | 5 | 40/1000 = 0.04 |
| **合计** | **1000** | | **1.00** |

**第一步：计算 Σ(pᵢ × i)**

```
= 0.60×1 + 0.20×2 + 0.10×3 + 0.06×4 + 0.04×5
= 0.60   + 0.40   + 0.30   + 0.24   + 0.20
= 1.74
```

**第二步：代入公式**

```
ECS = 2 × 1.74 − 1 = 2.48
```

**解读**：虽然真实有 5 条视频，但因为 A 占了 60% 的曝光，实际上**等效于均匀推了 2.48 条视频**。头部集中效应吃掉了 5 − 2.48 = 2.52 条视频的"有效性"。

### 验证两个极端

**极端 1：完全集中**（A 占 100%）

| 视频 | 占比 pᵢ | 排名 i |
|---|---|---|
| A | 1.00 | 1 |
| B~E | 0.00 | 2~5 |

```
Σ(pᵢ × i) = 1.00×1 + 0×2 + 0×3 + 0×4 + 0×5 = 1.00
ECS = 2×1.00 − 1 = 1
```

ECS = 1，等效只有 1 条视频 ✓

**极端 2：完全均匀**（每条各 200 次，各占 20%）

| 视频 | 占比 pᵢ | 排名 i |
|---|---|---|
| A~E | 各 0.20 | 1~5 |

```
Σ(pᵢ × i) = 0.20×1 + 0.20×2 + 0.20×3 + 0.20×4 + 0.20×5
          = 0.20 × (1+2+3+4+5)
          = 0.20 × 15
          = 3.00
ECS = 2×3.00 − 1 = 5
```

ECS = 5 = N，所有视频等效全部被推 ✓

---

## 二、ecs_ratio — 分发均匀度比率

### 含义

"ECS 占真实视频池子的几成。去掉池子大小的影响后，只看**分布形态有多均匀**。"

### 公式

```
ecs_ratio = ECS / distinct_vid_cnt
```

其中 `distinct_vid_cnt` = 桶内当天被曝光的去重视频数。

### 值域

- **(0, 1]**（通常以百分比展示）
- → 100%：完全均匀
- → 0%：完全集中在一条视频

### 举例计算（接上面的例子）

```
ecs_ratio = ECS / N = 2.48 / 5 = 0.496 = 49.6%
```

**解读**：分发的均匀度达到了理想值的 49.6%。

### 实际数据中的量级

你们的短视频 Feed：
```
distinct_vid_cnt ≈ 16,000
ECS ≈ 1,150
ecs_ratio ≈ 1,150 / 16,000 ≈ 7.2%
```

意思是："**菜单上有 1.6 万条视频，但实际等效只推了约 1,150 条**，均匀度是 7.2%。"

### 三者的关系

```
ECS = distinct_vid_cnt × ecs_ratio
```

| 量 | 含义 | 类比 |
|---|---|---|
| `distinct_vid_cnt` | 菜单有多少道菜 | 池子大小 |
| `ecs_ratio` | 每道菜是否都有人点 | 分配均匀度 |
| `ECS` | 这家店实际在"运营"多少道菜 | 池子 × 均匀度 |

### 为什么需要 ecs_ratio 而不只看 ECS

**场景**：A 组 ECS = 1100，B 组 ECS = 1200。看 ECS 觉得 B 更分散。

但如果：
- A 组 `distinct_vid_cnt` = 15,000 → `ecs_ratio = 7.33%`
- B 组 `distinct_vid_cnt` = 18,000 → `ecs_ratio = 6.67%`

**真相是 A 的分布形态更均匀**，B 只是池子更大。

**结论**：
- 跨组/跨天比较 → 看 `ecs_ratio`（去掉池子大小干扰）
- 向老板解释 → 说 `ECS`（"等效推了 1150 条视频"更直观）
- 诊断问题 → 两个一起拆（ECS 跌了是池子小了还是形态变集中了？）

---

## 三、ARP（Average Recommendation Popularity）— 平均推荐热度

### 含义

"用户每次刷到一条推荐，这条视频在全平台当天有多火。**按曝光次数加权的平均热度**。"

### 公式

```
          Σ(桶内曝光次数ᵢ × 全平台曝光次数ᵢ)
ARP = ────────────────────────────────────────
                Σ 桶内曝光次数ᵢ
```

其中：
- `i` 遍历桶内所有被曝光的视频
- `桶内曝光次数ᵢ` = 这条视频在**这个桶**内被推了几次
- `全平台曝光次数ᵢ` = 这条视频在**全平台**当天被推了几次（= 它的"热门度"）

### 为什么要加权

因为每一次"推荐事件"对用户体验的贡献是等权的。如果一条视频被推了 500 次，它对"用户平均看到什么"的影响就是另一条只推了 10 次的视频的 50 倍。

### 举例计算

假设某个桶当天推了 3 条视频：

| 视频 | 桶内曝光 | 全平台曝光（热度） | 桶内曝光 × 全平台曝光 |
|---|---|---|---|
| A（爆款） | 500 | 200,000 | 500 × 200,000 = 100,000,000 |
| B（中等） | 300 | 50,000 | 300 × 50,000 = 15,000,000 |
| C（长尾） | 200 | 3,000 | 200 × 3,000 = 600,000 |
| **合计** | **1,000** | | **115,600,000** |

**代入公式**：

```
         115,600,000
ARP = ──────────────── = 115,600
            1,000
```

**解读**：这个桶推给用户的视频，**平均每条在全平台当天被推了 11.56 万次**。比较偏头部——因为 A（20 万次爆款）被推了 500 次，权重最大。

### 对比：如果不加权（简单平均）

```
简单平均 = (200,000 + 50,000 + 3,000) / 3 = 84,333
```

加权后 ARP = 115,600 > 简单平均 84,333。差异来自 A 视频被推得多（500 次），拉高了加权值。

**这个差异就是"用户真实体验的热度" vs "视频池子本身的热度"之间的差**。ARP 反映的是前者。

### 值域和解读

- **没有绝对好坏**，只能同日同组比较
- 你们当前 ARP 在 **12 万左右**
- 两组之间差异 > 0.5% 就是显著信号（这是所有指标里噪声最小的）

---

## 四、三个指标的综合应用

### 完整的诊断思路

```
Step 1:  看 bn_rov / cn_rov / total_rov  →  数值赢没赢？
Step 2:  看 ecs_ratio                     →  分发有没有变集中？
Step 3:  看 ARP                           →  推的内容有没有变头部？
Step 4:  结合判断                          →  落在四象限的哪个位置？
```

### 四象限诊断矩阵

|  | ARP ↓（推更长尾） | ARP ↑（推更头部） |
|---|---|---|
| **ecs_ratio ↑**（更分散） | ✅ **最健康**：分散推长尾 = 真·个性化 | ⚠️ **可接受**：分散但推头部 |
| **ecs_ratio ↓**（更集中） | ❓ **少见**：集中推长尾 | ❌ **最差**：集中推头部 = 作弊 |

### 用真实数据走一遍

以建模目标实验 01 桶（8 天均值 vs 对照组 89）为例：

| 指标 | 01 桶值 | 89 桶值 | 相对差 |
|---|---|---|---|
| bn_rov | 0.04115 | 0.03840 | **+7.95%** |
| cn_rov | 0.00912 | 0.00844 | **+11.43%** |
| total_rov | 0.07491 | 0.07057 | **+7.35%** |
| ecs_ratio | 7.11% | 7.23% | **+1.02%**（更分散）|
| ARP | 133,856 | 131,685 | **-0.36%**（推更少头部）|

**诊断**：
- Step 1: 数值全面赢（bn +8%, cn +11%, total +7%）✅
- Step 2: ecs_ratio +1%（更分散，没有集中）✅
- Step 3: ARP -0.4%（推更少头部）✅
- Step 4: 落在**左上象限**（分散 + 长尾）= **最健康**

**汇报一句话**：
> "bn_rov 涨 8%，**不是靠推头部换的**——ecs_ratio 反而升了（更分散），ARP 反而降了（推更少爆款）。这是真·个性化提升。"

---

## 五、SQL 实现速查

### ECS 计算（`t_bucket_ecs` CTE）

```sql
-- 内层：算每条 vid 的占比 p 和降序排名 rn
SELECT  vid_exp_cnt / SUM(vid_exp_cnt) OVER (
            PARTITION BY dt, apptype, abcode, suffix
        ) AS p
        ,ROW_NUMBER() OVER (
            PARTITION BY dt, apptype, abcode, suffix
            ORDER BY vid_exp_cnt DESC
        ) AS rn
FROM    t_vid_exp

-- 外层：公式 2·Σ(p·rn) - 1
SELECT  2 * SUM(p * rn) - 1 AS ecs
GROUP BY dt, apptype, abcode, suffix
```

### ecs_ratio 计算（`t_metrics` 内）

```sql
ROUND(AVG(ecs) / NULLIF(AVG(distinct_vid_cnt), 0), 6) AS ecs_ratio
```

### ARP 计算（`t_bucket_arp` CTE）

```sql
-- 分子：桶内曝光 × 全平台曝光；分母：桶内总曝光
SELECT  SUM(v.vid_exp_cnt * g.vid_global_pop)
      / SUM(v.vid_exp_cnt) AS arp
FROM    t_vid_exp v
LEFT JOIN t_vid_global_pop g
ON      v.vid = g.vid AND v.dt = g.dt
GROUP BY v.dt, v.apptype, v.abcode, v.suffix
```

---

## 六、噪声基底（实测值，用于判断信号显著性）

基于对照组内部 89 vs 2c 的 8 天实测：

| 指标 | 噪声门槛 | 低于此值视为噪声 |
|---|---|---|
| ecs_ratio | **2.88%** | 组间差异 < 2.9% 不显著 |
| ARP | **0.43%** | 组间差异 < 0.5% 不显著 |
| bn_rov | **1.10%** | 组间差异 < 1.1% 不显著 |
| cn_rov | **4.10%** | cn 噪声最大，< 4% 不显著 |
| total_rov | **1.79%** | 组间差异 < 1.8% 不显著 |

**用法**：每次看数据，先查这张表。低于门槛的差异不要汇报为"发现"。
