Skill 寫法圖鑑

algo-rank-elo

asgard-ai-platform | 資料與分析 | 原文 | MIT

用 Elo 評分從一對一比較結果替對象排名

中文翻譯

---
name: "algo-rank-elo"
description: "實作 Elo 評分系統,從成對比較的結果替項目或玩家排名。當使用者需要從一對一對戰結果排名、建立競技評分系統、或從比較資料評估相對品質時使用,即使他們說的是「玩家評分」、「從比較中排名」或「競技計分系統」也一樣。"
metadata:
  category: "WP-44 排名演算法"
  tags: ["ranking", "elo", "pairwise-comparison", "rating-system"]
---

# Elo 評分系統

## 概述

Elo 給每個對象一個數值評分,每次成對比較後更新。贏家加分、輸家扣分。交換的分數多寡,取決於預期結果和實際結果的差距。原本用在西洋棋,現在用在運動、遊戲和 A/B 偏好測試。每場比賽的更新是 O(1)。

## 何時使用

**觸發條件:**
- 要從成對比較資料(A 對 B 的結果)替項目排名
- 要替遊戲或運動建立競技評分系統
- 透過成對偏好做群眾外包的品質評估

**何時不要用:**
- 手上是絕對分數而不是成對比較時(直接排名就好)
- 團隊動態比個人實力更重要時(用 TrueSkill)

## 演算法

```
鐵律:Elo 假設每場對戰都是獨立且平穩的
評分的變動取決於「意外程度」:打敗評分較高的對手,
得到的分數比打敗評分較低的多。K 因子控制更新速度:
高 K(32)= 波動大、適應快。低 K(16)= 穩定、適應慢。
要依實力變化的快慢來選 K。
```

### 階段 1:輸入驗證
把所有參與者初始化為基準評分(通常是 1500)。蒐集比賽結果:贏家、輸家(或平手)。
**關卡:** 比賽資料有效、沒有自己對自己的比賽。

### 階段 2:核心演算法
1. 預期得分:E_A = 1 / (1 + 10^((R_B - R_A)/400))
2. 實際得分:S_A = 1(贏)、0.5(平手)、0(輸)
3. 更新:R_A_new = R_A + K × (S_A - E_A)
4. 依序處理所有比賽(循序式 Elo 的處理順序會影響結果)

### 階段 3:驗證
檢查:評分總點數守恆(零和)。評分分布合理(沒有因資料錯誤造成的極端值)。
**關卡:** 評分守恆、榜首項目通過健全性檢查。

### 階段 4:輸出
回傳排序後的評分,並附上信心指標。

## 輸出格式

```json
{
  "ratings": [{"id": "player_A", "rating": 1720, "matches": 50, "wins": 35, "losses": 15}],
  "metadata": {"k_factor": 32, "initial_rating": 1500, "total_matches": 500}
}
```

## 範例

### 輸入輸出範例
**輸入:** 玩家 A(1500)打敗玩家 B(1500),K=32
**預期:** E_A = 0.5,S_A = 1。R_A_new = 1500 + 32×(1-0.5) = 1516。R_B_new = 1484。

### 邊界情況
| 輸入 | 預期 | 原因 |
|-------|----------|-----|
| 1500 打敗 2000 | 評分大幅上升(K=32 時約 29 分) | 爆冷門,意外程度大 |
| 2000 打敗 1500 | 評分小幅上升(K=32 時約 3 分) | 結果在預期內,意外程度極小 |
| 實力相當的雙方平手 | 沒有變動 | 預期結果和實際結果完全一致 |

## 常見陷阱

- **K 因子的選擇**:太高 = 評分來回震盪。太低 = 反映實力變化太慢。可以用變動的 K:新參與者高一點,老手低一點。
- **順序相依**:循序式 Elo 的評分取決於比賽的處理順序。要做批次處理的話,用迭代式 Elo 或 Bradley-Terry 模型。
- **通膨/通縮**:在參與者會進出的開放系統裡,平均評分可能漂移。要用評分下限或定期校準。
- **不是為團隊設計的**:標準 Elo 是 1 對 1。團隊的話,可以取團隊評分平均,或用 TrueSkill,它會對團隊內個人的貢獻建模。
- **評分 ≠ 勝率**:200 分的評分差距,代表預期勝率約 76%,但實際結果還是取決於情境、狀態和運氣。

## 腳本

| 腳本 | 說明 | 用法 |
|--------|-------------|-------|
| `scripts/elo.py` | 更新 Elo 評分(單場或批次),並做零和驗證 | `python scripts/elo.py --help` |

執行 `python scripts/elo.py --verify` 可以跑內建的健全性測試。

## 參考資料

- Bradley-Terry 模型(批次 Elo),見 `references/bradley-terry.md`
- 變動 K 因子的策略,見 `references/variable-k.md`

英文原文

---
name: "algo-rank-elo"
description: "Implement Elo rating system to rank items or players from pairwise comparison outcomes. Use this skill when the user needs to rank items from head-to-head matchups, build a competitive rating system, or evaluate relative quality from comparison data — even if they say 'player rating', 'ranking from comparisons', or 'competitive scoring system'."
metadata:
  category: "WP-44 排名演算法"
  tags: ["ranking", "elo", "pairwise-comparison", "rating-system"]
---

# Elo Rating System

## Overview

Elo assigns numerical ratings that update after each pairwise comparison. Winner gains points, loser loses points. The amount exchanged depends on expected vs actual outcome. Originally for chess, now used for sports, games, and A/B preference testing. Update runs in O(1) per match.

## When to Use

**Trigger conditions:**
- Ranking items from pairwise comparison data (A vs B outcomes)
- Building competitive rating systems for games or sports
- Crowdsourced quality evaluation through pairwise preferences

**When NOT to use:**
- When you have absolute scores, not pairwise comparisons (use direct ranking)
- When team dynamics matter more than individual skill (use TrueSkill)

## Algorithm

```
IRON LAW: Elo Assumes Each Matchup Is Independent and Stationary
Rating changes are based on surprise: beating a higher-rated opponent
gains more points than beating a lower-rated one. K-factor controls
update speed: high K (32) = volatile, fast adaptation. Low K (16) =
stable, slow adaptation. Choose K based on how quickly skill changes.
```

### Phase 1: Input Validation
Initialize all participants at base rating (typically 1500). Collect match results: winner, loser (or draw).
**Gate:** Valid match data, no self-matches.

### Phase 2: Core Algorithm
1. Expected score: E_A = 1 / (1 + 10^((R_B - R_A)/400))
2. Actual score: S_A = 1 (win), 0.5 (draw), 0 (loss)
3. Update: R_A_new = R_A + K × (S_A - E_A)
4. Process all matches sequentially (order matters for sequential Elo)

### Phase 3: Verification
Check: total rating points conserved (zero-sum). Rating distribution is reasonable (no extreme values from data errors).
**Gate:** Ratings conserved, top-ranked items pass sanity check.

### Phase 4: Output
Return sorted ratings with confidence indicators.

## Output Format

```json
{
  "ratings": [{"id": "player_A", "rating": 1720, "matches": 50, "wins": 35, "losses": 15}],
  "metadata": {"k_factor": 32, "initial_rating": 1500, "total_matches": 500}
}
```

## Examples

### Sample I/O
**Input:** Player A (1500) beats Player B (1500), K=32
**Expected:** E_A = 0.5, S_A = 1. R_A_new = 1500 + 32×(1-0.5) = 1516. R_B_new = 1484.

### Edge Cases
| Input | Expected | Why |
|-------|----------|-----|
| 1500 beats 2000 | Large rating gain (~29 pts at K=32) | Huge upset, large surprise |
| 2000 beats 1500 | Small rating gain (~3 pts at K=32) | Expected outcome, minimal surprise |
| Draw between equals | No change | Expected outcome exactly matches actual |

## Gotchas

- **K-factor selection**: Too high = ratings oscillate. Too low = slow to reflect actual skill changes. Use variable K: higher for new participants, lower for established ones.
- **Order dependence**: Sequential Elo ratings depend on match processing order. For batch processing, use iterative Elo or Bradley-Terry model.
- **Inflation/deflation**: In open systems where participants enter/leave, average rating can drift. Use rating floors or periodic calibration.
- **Not designed for teams**: Standard Elo is for 1v1. For teams, average team ratings or use TrueSkill which models individual contribution within teams.
- **Rating ≠ win probability**: A 200-point rating gap implies ~76% expected win rate, but actual outcomes depend on context, form, and luck.

## Scripts

| Script | Description | Usage |
|--------|-------------|-------|
| `scripts/elo.py` | Update Elo ratings (single match or batch) with zero-sum verification | `python scripts/elo.py --help` |

Run `python scripts/elo.py --verify` to execute built-in sanity tests.

## References

- For Bradley-Terry model (batch Elo), see `references/bradley-terry.md`
- For variable K-factor strategies, see `references/variable-k.md`