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 類型全名特性預設
vesdeVariance Exploding SDE (方差爆炸 SDE)σ(t) 從小到大指數增長預設
vpsdeVariance Preserving SDE (方差保持 SDE)β(t) 線性增長,整體方差受控
subvpsdeSub-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 是加入的噪聲。訓練流程:

  1. 對每筆 (x, y) 重複 n_repeats 次(預設 30)
  2. 對每個重複,隨機取 t ~ U(ε, 1)z ~ N(0, I)
  3. 計算 y_perturbed = mean(y, t) + σ(t) * z
  4. 組合預測器 [y_perturbed, x, t] → 目標 [-z]
  5. 對每個 y_dim 訓練一個獨立的 LightGBM Regressor

2.4 逆向取樣 (Reverse Sampling)

取樣時執行逆向 SDE:

  1. 從先驗分佈 y_T ~ N(0, σ²_max) 取樣
  2. 使用 Euler-Maruyama 求解器 (Solver),從 t=Tt=0 逐步去噪
  3. 每一步利用 Score Model 估計梯度方向
  4. 最終得到 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 依賴清單

套件版本需求用途
lightgbm4.3.0(固定版本)Score Function 的樹模型後端
scikit-learn1.5.0(固定版本)資料分割、KDE、BaseEstimator 介面
numpy>=1.24數值計算
scipy>=1.13統計分佈
pandas>=2.0DataFrame 支援
einops>=0.8.0張量重排
jaxtyping>=0.2.19型別標註(純文件用,不需 JAX)
tqdm>=4.66進度條

注意lightgbmscikit-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 表格工具的比較

維度TreeffuserTabDDPMForestDiffusionTabDiffTabCSDI
任務條件分佈預測 p(y|x)合成資料生成 p(x)合成資料生成 p(x)合成資料生成 p(x)缺失值填補 p(x_miss|x_obs)
Score 後端LightGBM(樹)MLP(神經網路)XGBoost/Random ForestTransformerTransformer
GPU 需求不需要需要不需要需要需要
多維目標支援(獨立 y_dim)支援支援支援支援
類別特徵原生支援需 One-hot原生支援需 Encoding需 Encoding
APIscikit-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 生態系中,它可以扮演以下角色:

  1. Conditional Sampler (條件取樣器) — 固定特徵 x,生成 y 的合成樣本
  2. Distribution-Aware Augmentation (分佈感知擴增) — 了解 y|x 的完整分佈後,可以生成更真實的合成資料
  3. 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 APIfit() / 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 的設計可以看到幾個尚未被開源工具覆蓋的方向:

  1. Conditional SDG with Distribution Awareness — 把 Treeffuser 的條件分佈建模能力整合進 SDG 框架,讓合成資料不只匹配邊際分佈,還匹配條件分佈
  2. Tree-based Diffusion for Joint Generation — ForestDiffusion 做了一步,但尚缺成熟的 scikit-learn 風格封裝
  3. SDG Quality Metric: Conditional Distribution Fidelity — SDMetrics 缺少條件分佈一致性指標,Treeffuser 概念可填補
  4. 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}