Treeffuser 完整教學
Repository: https://github.com/blei-lab/treeffuser Stars: 56 | Forks: 10 | License: MIT Paper: NeurIPS 2024 — arXiv:2406.07658 Tags: diffusion-models, gradient-boosting, probabilistic-prediction, tabular-data, lightgbm, heteroscedasticity 最後更新: 2026-04-28 作者群: David Blei Lab @ Columbia University(Nicolas Beltran-Velez, Alessandro Grande, Achille Nazaret, Alp Kucukelbir, David Blei)
2. 核心架構 (Core Architecture)
2.1 架構總覽
graph TB
subgraph Training["訓練階段 (Training Phase)"]
D[("原始資料
(X, y)")] --> R["資料重複擴增
n_repeats × (X, y)"]
R --> N["前向擴散加噪
y → y_perturbed
+ 隨機 t ~ U(0,1)"]
N --> T["訓練 LightGBM
score(y_perturbed, x, t)"]
T --> S["Score Model
(每個 y_dim 一個 LightGBM)"]
end
subgraph Inference["推論階段 (Sampling Phase)"]
P["先驗分佈取樣
y_T ~ N(0, σ²)"] --> ODE["逆向 SDE 求解
Euler-Maruyama"]
S --> ODE
X_new["新特徵 x_new"] --> ODE
ODE --> Y_samples["條件樣本
y_samples ~ p(y|x_new)"]
end
subgraph Analysis["分析階段 (Analysis Phase)"]
Y_samples --> Samples["Samples 物件"]
Samples --> Mean["條件均值"]
Samples --> Std["條件標準差"]
Samples --> Q["條件分位數"]
Samples --> CI["信賴區間"]
Samples --> KDE["核密度估計"]
end
style Training fill:#e8f4fd,stroke:#1a73e8
style Inference fill:#fce8e8,stroke:#e81a1a
style Analysis fill:#e8fce8,stroke:#1ae81a
2.2 前向擴散過程 (Forward Diffusion Process)
Treeffuser 支援三種 Stochastic Differential Equation (SDE; 隨機微分方程):
| SDE 類型 | 全名 | 特性 | 預設 |
|---|---|---|---|
vesde | Variance Exploding SDE (方差爆炸 SDE) | σ(t) 從小到大指數增長 | 預設 |
vpsde | Variance Preserving SDE (方差保持 SDE) | β(t) 線性增長,整體方差受控 | — |
subvpsde | Sub-Variance Preserving SDE | β(t) 更保守的增長 | — |
前向過程將資料逐步加噪:dy = drift(y, t) dt + diffusion(t) dW
轉移核 (Transition Kernel) p_t(y|y₀) 是高斯分佈,均值和標準差可由 SDE 參數解析計算,因此訓練標籤可直接算出(無需 MCMC)。
2.3 Score Function 訓練
核心等式:
1score(y_perturbed, x, t) = GBT(y_perturbed, x, t) / σ(t)
訓練時的去噪目標 (Denoising Objective):
1L = || GBT(y_perturbed, x, t) - (-z) ||²
其中 z 是加入的噪聲。訓練流程:
- 對每筆
(x, y)重複n_repeats次(預設 30) - 對每個重複,隨機取
t ~ U(ε, 1)和z ~ N(0, I) - 計算
y_perturbed = mean(y, t) + σ(t) * z - 組合預測器
[y_perturbed, x, t]→ 目標[-z] - 對每個
y_dim訓練一個獨立的 LightGBM Regressor
2.4 逆向取樣 (Reverse Sampling)
取樣時執行逆向 SDE:
- 從先驗分佈
y_T ~ N(0, σ²_max)取樣 - 使用 Euler-Maruyama 求解器 (Solver),從
t=T到t=0逐步去噪 - 每一步利用 Score Model 估計梯度方向
- 最終得到
y_0 ~ p(y|x)
2.5 檔案結構
1treeffuser/
2├── src/treeffuser/
3│ ├── __init__.py # 匯出 Treeffuser, Samples
4│ ├── treeffuser.py # 主類別:參數定義、SDE/Score 工廠
5│ ├── _base_tabular_diffusion.py # 基礎類別:fit/sample/predict 流程
6│ ├── _score_models.py # LightGBMScoreModel 訓練邏輯
7│ ├── _scaler.py # 混合型特徵標準化
8│ ├── _warnings.py # 收斂警告定義
9│ ├── samples.py # Samples 統計工具類別
10│ └── sde/
11│ ├── base_sde.py # SDE 抽象基礎類別
12│ ├── base_solver.py # SDE Solver 抽象類別 + 註冊器
13│ ├── diffusion_sdes.py # VESDE / VPSDE / SubVPSDE 實作
14│ ├── initialize.py # 從資料初始化 SDE 超參數
15│ ├── parameter_schedule.py # 線性/指數排程
16│ └── solvers.py # Euler-Maruyama 求解器
17├── examples/ # 範例 Notebook
18├── testbed/ # 論文基準測試框架
19└── pyproject.toml # Poetry 管理,依賴 LightGBM 4.3.0
3. 安裝與設定 (Installation & Setup)
3.1 基本安裝
1# 建議使用 uv 建立隔離環境
2uv venv treeffuser-env --python 3.11
3source treeffuser-env/bin/activate
4
5# 從 PyPI 安裝
6uv pip install treeffuser
7
8# 或從 GitHub 安裝開發版
9uv pip install git+https://github.com/blei-lab/treeffuser.git@main
3.2 依賴清單
| 套件 | 版本需求 | 用途 |
|---|---|---|
lightgbm | 4.3.0(固定版本) | Score Function 的樹模型後端 |
scikit-learn | 1.5.0(固定版本) | 資料分割、KDE、BaseEstimator 介面 |
numpy | >=1.24 | 數值計算 |
scipy | >=1.13 | 統計分佈 |
pandas | >=2.0 | DataFrame 支援 |
einops | >=0.8.0 | 張量重排 |
jaxtyping | >=0.2.19 | 型別標註(純文件用,不需 JAX) |
tqdm | >=4.66 | 進度條 |
注意:
lightgbm和scikit-learn的版本被釘死,可能與其他套件衝突。安裝時建議使用獨立虛擬環境。
3.3 驗證安裝
1from treeffuser import Treeffuser, Samples
2import numpy as np
3
4# 快速驗證
5rng = np.random.default_rng(42)
6X = rng.normal(size=(100, 3))
7y = X[:, 0] + rng.normal(scale=0.1, size=100)
8model = Treeffuser(n_estimators=100, n_repeats=5, seed=42)
9model.fit(X, y)
10samples = model.sample(X[:5], n_samples=10, seed=42)
11print(f"取樣完成:shape = {samples.shape}") # (10, 5)
4. 使用方式與程式碼範例 (Usage & Code Examples)
4.1 範例一:異質變異性迴歸 (Heteroscedastic Regression)
此範例展示 Treeffuser 如何捕捉變異數隨特徵變化的分佈——這在藥物劑量-反應研究中非常常見。
1import numpy as np
2import matplotlib.pyplot as plt
3from treeffuser import Treeffuser, Samples
4
5# 模擬藥物劑量-反應資料
6# 高劑量時反應較一致,低劑量時變異大(heteroscedastic)
7seed = 42
8rng = np.random.default_rng(seed)
9n = 3000
10
11dose = rng.uniform(0.1, 10.0, size=n) # 劑量 (mg/kg)
12response_mean = 100 * (1 - np.exp(-0.5 * dose)) # Emax 模型
13response_std = 20 / (1 + dose) # 低劑量高變異
14response = response_mean + rng.normal(scale=response_std, size=n)
15
16# 訓練 Treeffuser
17model = Treeffuser(
18 n_estimators=2000, # LightGBM 迭代次數
19 n_repeats=30, # 每筆資料產生 30 個加噪版本
20 early_stopping_rounds=50,
21 seed=seed,
22)
23model.fit(dose, response)
24
25# 在測試點上取樣條件分佈
26dose_test = np.linspace(0.5, 9.5, 50)
27y_samples = model.sample(dose_test, n_samples=200, seed=seed, verbose=True)
28samples_obj = Samples(y_samples)
29
30# 計算統計量
31y_mean = samples_obj.sample_mean()
32y_q05, y_q95 = samples_obj.sample_quantile(q=[0.05, 0.95])
33
34# 視覺化
35fig, ax = plt.subplots(figsize=(10, 6))
36ax.scatter(dose, response, s=1, alpha=0.3, label="觀測資料")
37ax.plot(dose_test, y_mean, "r-", linewidth=2, label="條件均值 E[y|x]")
38ax.fill_between(dose_test, y_q05, y_q95, alpha=0.3, color="red",
39 label="90% 預測區間")
40ax.set_xlabel("劑量 (mg/kg)")
41ax.set_ylabel("藥物反應")
42ax.set_title("Treeffuser:異質變異性劑量-反應預測")
43ax.legend()
44plt.tight_layout()
45plt.savefig("dose_response_treeffuser.png", dpi=150)
4.2 範例二:多模態條件分佈 (Bimodal Patient Subgroups)
模擬兩群患者(有反應 vs 無反應)的治療結果預測——臨床試驗中常見的「responder / non-responder」分群。
1import numpy as np
2from treeffuser import Treeffuser, Samples
3
4seed = 42
5rng = np.random.default_rng(seed)
6n = 5000
7
8# 特徵:年齡、BMI、基因分數
9age = rng.uniform(30, 70, n)
10bmi = rng.uniform(18, 35, n)
11gene_score = rng.uniform(0, 1, n)
12
13X = np.column_stack([age, bmi, gene_score])
14
15# 雙模態反應:gene_score > 0.5 的族群反應良好
16responder_prob = 1 / (1 + np.exp(-5 * (gene_score - 0.5)))
17is_responder = rng.binomial(1, responder_prob)
18
19# 有反應者:腫瘤縮小 40-60%;無反應者:縮小 0-10%
20tumor_shrinkage = np.where(
21 is_responder,
22 rng.normal(50, 8, n), # 有反應者
23 rng.normal(5, 5, n), # 無反應者
24)
25
26# 訓練
27model = Treeffuser(n_estimators=2000, n_repeats=30, seed=seed)
28model.fit(X, tumor_shrinkage)
29
30# 對兩種極端患者取樣
31patient_responder = np.array([[50, 25, 0.9]]) # 高基因分數
32patient_non_resp = np.array([[50, 25, 0.1]]) # 低基因分數
33patient_mixed = np.array([[50, 25, 0.5]]) # 邊界基因分數
34
35n_samples = 500
36samples_r = model.sample(patient_responder, n_samples=n_samples, seed=seed)
37samples_n = model.sample(patient_non_resp, n_samples=n_samples, seed=seed)
38samples_m = model.sample(patient_mixed, n_samples=n_samples, seed=seed)
39
40# 分析:邊界患者的分佈應該是雙峰的
41samples_mixed = Samples(samples_m)
42print(f"邊界患者 - 均值: {samples_mixed.sample_mean()[0]:.1f}%")
43print(f"邊界患者 - 標準差: {samples_mixed.sample_std()[0]:.1f}%")
44q05, q95 = samples_mixed.sample_quantile(q=[0.05, 0.95])
45print(f"邊界患者 - 90% CI: [{q05[0]:.1f}%, {q95[0]:.1f}%]")
46# 使用 KDE 觀察雙峰結構
47kde = samples_mixed.sample_kde()
4.3 範例三:多變量預測 + 下游決策 (Multivariate + News Vendor)
Treeffuser 支援多維目標預測,搭配下游成本函數做決策最佳化。此範例模擬同時預測兩個 PK 參數 (AUC, Cmax)。
1import numpy as np
2from treeffuser import Treeffuser, Samples
3
4seed = 42
5rng = np.random.default_rng(seed)
6n = 2000
7
8# 特徵:體重、年齡、CYP 酵素活性
9weight = rng.uniform(50, 100, n)
10age = rng.uniform(20, 80, n)
11cyp_activity = rng.uniform(0.5, 2.0, n)
12X = np.column_stack([weight, age, cyp_activity])
13
14# 目標:同時預測 AUC 和 Cmax(二維目標)
15clearance = 10 * cyp_activity / (weight ** 0.75)
16auc = 500 / clearance + rng.normal(0, 20, n)
17cmax = 50 / clearance + rng.normal(0, 5, n)
18y = np.column_stack([auc, cmax])
19
20# 訓練(多維目標)
21model = Treeffuser(n_estimators=1500, n_repeats=20, seed=seed)
22model.fit(X, y)
23
24# 為新患者預測 PK 參數聯合分佈
25new_patient = np.array([[70, 45, 1.2]])
26pk_samples = model.sample(new_patient, n_samples=1000, seed=seed)
27# pk_samples.shape = (1000, 1, 2) → 1000 個 (AUC, Cmax) 樣本
28
29# 下游決策:劑量調整
30# 若超過 80% 樣本的 Cmax 在安全範圍內,建議該劑量
31cmax_samples = pk_samples[:, 0, 1]
32safe_fraction = np.mean(cmax_samples < 100) # Cmax < 100 為安全
33print(f"安全範圍內的機率: {safe_fraction:.1%}")
34print(f"AUC 均值: {pk_samples[:, 0, 0].mean():.1f}")
35print(f"Cmax 均值: {cmax_samples.mean():.1f}")
36
37# 利用樣本做 Cost-Sensitive 決策
38# 過高 → 毒性成本 10 倍 vs 過低 → 療效不足成本 1 倍
39cost_overshoot = 10 * np.maximum(0, cmax_samples - 100)
40cost_undershoot = 1 * np.maximum(0, 50 - cmax_samples)
41expected_cost = (cost_overshoot + cost_undershoot).mean()
42print(f"期望成本: {expected_cost:.2f}")
5. 在 SDG 生態系中的定位 (Position in the SDG Ecosystem)
5.1 與其他 Diffusion-based 表格工具的比較
| 維度 | Treeffuser | TabDDPM | ForestDiffusion | TabDiff | TabCSDI |
|---|---|---|---|---|---|
| 任務 | 條件分佈預測 p(y|x) | 合成資料生成 p(x) | 合成資料生成 p(x) | 合成資料生成 p(x) | 缺失值填補 p(x_miss|x_obs) |
| Score 後端 | LightGBM(樹) | MLP(神經網路) | XGBoost/Random Forest | Transformer | Transformer |
| GPU 需求 | 不需要 | 需要 | 不需要 | 需要 | 需要 |
| 多維目標 | 支援(獨立 y_dim) | 支援 | 支援 | 支援 | 支援 |
| 類別特徵 | 原生支援 | 需 One-hot | 原生支援 | 需 Encoding | 需 Encoding |
| API | scikit-learn | 自訂 | 自訂 | 自訂 | 自訂 |
| 星數 | 56 | ~700+ | ~200+ | ~50 | ~150+ |
5.2 定位差異
Treeffuser 和其他 Diffusion-based 表格工具有一個根本差異:
- 大多數工具做的是 Unconditional/Joint Density Estimation (無條件/聯合密度估計)
p(x)— 目標是生成與原始資料分佈一致的合成表格 - Treeffuser 做的是 Conditional Prediction (條件預測)
p(y|x)— 目標是給定特徵後,預測目標的完整分佈
這意味著 Treeffuser 不是 SDG 工具,而是 Probabilistic Regression (機率迴歸) 工具。但在 SDG 生態系中,它可以扮演以下角色:
- Conditional Sampler (條件取樣器) — 固定特徵 x,生成 y 的合成樣本
- Distribution-Aware Augmentation (分佈感知擴增) — 了解 y|x 的完整分佈後,可以生成更真實的合成資料
- Evaluation Tool (評估工具) — 比較合成資料的條件分佈 vs 真實資料
5.3 在 Bio-SDG 管線中的角色
graph LR
subgraph 資料準備
A["原始臨床/實驗資料"] --> B["特徵工程"]
end
subgraph SDG 生成
B --> C["SDV / synthcity
生成合成表格"]
end
subgraph 品質驗證
C --> D["SDMetrics
統計相似度"]
C --> E["Treeffuser
p(y|x) 一致性檢驗"]
end
subgraph 下游應用
E -->|分佈一致| F["安全使用合成資料"]
E -->|分佈偏離| G["回饋調整 SDG 參數"]
G --> C
end
style E fill:#fff3cd,stroke:#ffc107,stroke-width:2px
Treeffuser 在 SDG 品質驗證中的獨特價值:不只比較邊際分佈 (Marginal Distribution),還能比較條件分佈 (Conditional Distribution) 是否被合成資料正確保留。
6. 與其他工具的整合 (Integration with Other SDG Tools)
6.1 搭配 SDV/synthcity 做條件分佈驗證
1# 虛擬碼:驗證合成資料是否保留了 p(y|x) 結構
2from treeffuser import Treeffuser
3import numpy as np
4
5# 1. 在真實資料上訓練 Treeffuser
6model_real = Treeffuser(seed=42)
7model_real.fit(X_real, y_real)
8
9# 2. 在合成資料上訓練另一個 Treeffuser
10model_synth = Treeffuser(seed=42)
11model_synth.fit(X_synth, y_synth)
12
13# 3. 在測試點上比較兩者的條件分佈
14X_test = X_real[:100]
15samples_real = model_real.sample(X_test, n_samples=500, seed=42)
16samples_synth = model_synth.sample(X_test, n_samples=500, seed=42)
17
18# 比較統計量
19from scipy.stats import ks_2samp
20ks_stats = [
21 ks_2samp(samples_real[:, i], samples_synth[:, i]).statistic
22 for i in range(len(X_test))
23]
24print(f"平均 KS 距離: {np.mean(ks_stats):.4f}")
6.2 搭配 ForestDiffusion
ForestDiffusion 和 Treeffuser 使用相似的樹模型後端,但任務不同:
- ForestDiffusion → 聯合分佈
p(x)→ 生成完整合成表格 - Treeffuser → 條件分佈
p(y|x)→ 條件預測/擴增
整合方式:用 ForestDiffusion 生成合成特徵 X_synth,再用 Treeffuser 生成對應的條件目標 y_synth。
6.3 搭配 AIKT 管線 (WP1-WP7)
| AIKT 階段 | Treeffuser 應用 |
|---|---|
| WP2 — 資料探索 | 分析 y|x 的條件分佈特性:是否多峰?是否異質變異? |
| WP3 — 合成資料 | 作為條件取樣器產生 label-aware 的合成反應值 |
| WP4 — 模型訓練 | 用 Treeffuser 預測區間取代 point estimate,改善不確定性量化 |
| WP5 — 評估 | 比較真實/合成資料的條件分佈一致性 |
6.4 與 SDMetrics 互補
SDMetrics 擅長的是邊際分佈和成對相關的比較。Treeffuser 可以彌補 SDMetrics 不檢查的高階條件關係:
1# SDMetrics: 邊際/成對評估
2from sdmetrics.reports.single_table import QualityReport
3report = QualityReport()
4report.generate(real_data, synth_data, metadata)
5
6# Treeffuser: 條件分佈評估(SDMetrics 不做這個)
7# → 檢查 p_synth(y|x) 是否 ≈ p_real(y|x)
7. 優缺點分析 (Strengths & Limitations)
7.1 優勢
| 優勢 | 說明 |
|---|---|
| 無需 GPU | 純 LightGBM 後端,CPU 就能訓練和推論 |
| 任意條件分佈 | 多模態、異質變異性、厚尾都能建模 |
| scikit-learn API | fit() / sample() 兩步上手,學習門檻極低 |
| 原生類別特徵 | LightGBM 天生支援,不需 One-hot Encoding |
| 理論基礎強 | NeurIPS 2024 發表、Blei Lab 出品 |
| Samples 工具類別 | 內建均值/標準差/分位數/CI/KDE 計算 |
| MIT License | 商業友善,可直接整合進內部管線 |
| 依賴輕量 | 無 PyTorch/TensorFlow/JAX 依賴 |
7.2 限制
| 限制 | 說明 | 影響程度 |
|---|---|---|
| 非 SDG 工具 | 只做 p(y|x) 條件預測,不做 p(x) 聯合生成 | 高 — 無法直接用來生成完整合成表格 |
| 取樣速度慢 | 逆向 SDE 需要多步迭代,每步都要呼叫 LightGBM | 中 — 可透過減少 n_estimators 緩解 |
| 版本釘死 | lightgbm==4.3.0, scikit-learn==1.5.0 可能衝突 | 中 — 建議獨立虛擬環境 |
| y_dim 獨立 | 多維目標的每個維度用獨立 LightGBM,忽略 y 維度間的相關 | 中 — 高維 y 的聯合結構可能失真 |
| 無隱私保證 | 不提供 Differential Privacy (差分隱私) 保護 | 中 — 合規需求時需額外加層 |
| 社群規模小 | 56 stars, 10 forks,文件和範例有限 | 低 — 但程式碼品質高、結構清晰 |
| 無串流/線上學習 | 全量 batch 訓練,無增量更新 | 低 — 典型學術工具的限制 |
7.3 適用場景判斷
1是否需要預測 p(y|x) 的完整分佈?
2├── 否 → 不需要 Treeffuser
3│ ├── 需要生成合成表格 → SDV / synthcity / ForestDiffusion
4│ └── 需要點預測 → LightGBM / XGBoost / sklearn
5└── 是
6 ├── 資料是表格型嗎?
7 │ ├── 否 → 用 Neural Network-based Diffusion
8 │ └── 是
9 │ ├── 不需 GPU? → Treeffuser (首選)
10 │ ├── y 維度間相關很重要? → 考慮 TabDDPM / 其他
11 │ └── 需要 DP 隱私? → dp_cgans 或自行加層
12 └── Treeffuser 適用
7.4 Blue Ocean 機會
從 Treeffuser 的設計可以看到幾個尚未被開源工具覆蓋的方向:
- Conditional SDG with Distribution Awareness — 把 Treeffuser 的條件分佈建模能力整合進 SDG 框架,讓合成資料不只匹配邊際分佈,還匹配條件分佈
- Tree-based Diffusion for Joint Generation — ForestDiffusion 做了一步,但尚缺成熟的 scikit-learn 風格封裝
- SDG Quality Metric: Conditional Distribution Fidelity — SDMetrics 缺少條件分佈一致性指標,Treeffuser 概念可填補
- Privacy-Preserving Probabilistic Prediction — Treeffuser + DP-GBT (差分隱私梯度提升樹) 的組合尚不存在
附錄:快速參考
API 速查
1from treeffuser import Treeffuser, Samples
2
3# 初始化(常用參數)
4model = Treeffuser(
5 n_repeats=30, # 擴增倍率
6 n_estimators=3000, # LightGBM 樹數量
7 early_stopping_rounds=50, # 早停輪次
8 sde_name="vesde", # SDE 類型
9 seed=42,
10)
11
12# 訓練
13model.fit(X, y) # X: (n, d), y: (n,) 或 (n, k)
14
15# 取樣
16y_samples = model.sample(
17 X_new, # (m, d)
18 n_samples=100, # 每個 x 取幾個樣本
19 seed=42,
20 verbose=True,
21) # 回傳 (100, m) 或 (100, m, k)
22
23# 統計分析
24s = Samples(y_samples)
25s.sample_mean() # 條件均值
26s.sample_std() # 條件標準差
27s.sample_quantile(q=[0.05, 0.95]) # 分位數
28s.sample_confidence_interval(confidence=0.95)
29s.sample_kde() # 核密度估計
30s.sample_apply(custom_fn) # 自訂統計量
引用
1@article{beltranvelez2024treeffuser,
2 title={Treeffuser: Probabilistic Predictions via Conditional Diffusions
3 with Gradient-Boosted Trees},
4 author={Nicolas Beltran-Velez and Alessandro Antonio Grande and
5 Achille Nazaret and Alp Kucukelbir and David Blei},
6 year={2024},
7 journal={NeurIPS 2024},
8 url={https://arxiv.org/abs/2406.07658},
9}
Comments