TabGAN (Tabular-data-generation) 完整教學
Repository: https://github.com/Diyago/Tabular-data-generation Stars: 570 | Forks: 83 | License: Apache-2.0 Language: Python | PyPI:
tabganTags: GAN, tabular-data, adversarial-filtering, deep-learning, machine-learning Paper: Tabular GANs for uneven distribution (arXiv:2010.00638) Live Demo: HuggingFace Spaces | Colab Notebook
2. 核心架構 (Core Architecture)
2.1 整體管線架構
TabGAN 的所有 Generator 共享統一的四階段管線 (Four-Stage Pipeline):
flowchart TB
subgraph INPUT["輸入層 (Input Layer)"]
train["train_df
訓練特徵"]
target["target_df
目標變數"]
test["test_df
測試特徵
(分佈對齊用)"]
end
subgraph PREPROCESS["Stage 1: 前處理 (Preprocess)"]
validate["DataFrame 驗證
欄位型態檢查"]
encode["類別編碼
(Categorical Encoding)"]
end
subgraph GENERATE["Stage 2: 生成 (Generate)"]
direction LR
gan["GANGenerator
(CTGAN)"]
diff["ForestDiffusion
Generator"]
llm["LLMGenerator
(GReaT / API)"]
bayes["BayesianGenerator
(Gaussian Copula)"]
orig["OriginalGenerator
(Random Sampling)"]
end
subgraph POSTPROCESS["Stage 3: 後處理 (Post-process)"]
quantile["分位數過濾
(Quantile Filtering)
bot=0.001, top=0.999"]
constraint["約束引擎
(Constraint Engine)
Range / Unique / Formula / Regex"]
end
subgraph ADVERSARIAL["Stage 4: 對抗過濾 (Adversarial Filter)"]
lgbm["LightGBM 分類器
區分 real vs synthetic"]
filter["移除被判為 synthetic
的樣本"]
end
subgraph OUTPUT["輸出層 (Output Layer)"]
synth_df["synthetic_df
合成特徵"]
synth_target["synthetic_target
合成目標"]
end
INPUT --> PREPROCESS
PREPROCESS --> GENERATE
GENERATE --> POSTPROCESS
POSTPROCESS --> ADVERSARIAL
ADVERSARIAL --> OUTPUT
style INPUT fill:#e8f4fd,stroke:#2196F3
style GENERATE fill:#fff3e0,stroke:#FF9800
style ADVERSARIAL fill:#fce4ec,stroke:#E91E63
style OUTPUT fill:#e8f5e9,stroke:#4CAF50
2.2 對抗過濾機制 (Adversarial Filtering Mechanism)
對抗過濾 (Adversarial Filtering) 是 TabGAN 的核心創新。原理是:用 LightGBM 訓練一個二分類器區分真實資料與合成資料。若一筆合成資料被高信心地判為「合成」,代表它偏離真實分佈太遠,應被移除。只有「騙過分類器」的合成樣本才被保留。
這個機制確保合成資料的分佈忠實度 (Distribution Fidelity),在藥物開發中尤為重要——合成的 PK 參數 (Pharmacokinetic Parameters; 藥動學參數) 或 scRNA-seq 基因表達值若偏離真實分佈,下游分析將失去意義。
2.3 專案檔案結構
1Tabular-data-generation/
2├── src/
3│ ├── tabgan/ # 核心套件
4│ │ ├── sampler.py # 所有 Generator 實作
5│ │ ├── abc_sampler.py # Generator 抽象基底類別
6│ │ ├── adversarial_model.py # LightGBM 對抗過濾
7│ │ ├── auto_synth.py # AutoSynth 自動比較
8│ │ ├── constraints.py # 約束引擎
9│ │ ├── privacy_metrics.py # 隱私指標 (DCR/NNDR/MI)
10│ │ ├── quality_report.py # 品質報告
11│ │ ├── llm_config.py # LLM API 設定
12│ │ ├── llm_api_client.py # LLM API 客戶端
13│ │ ├── hf_integration.py # HuggingFace Hub 整合
14│ │ ├── sklearn_transformer.py # sklearn Pipeline 整合
15│ │ ├── cli.py # CLI 入口
16│ │ ├── encoders.py # 資料編碼器
17│ │ └── utils.py # 工具函式
18│ ├── _ctgan/ # CTGAN 核心實作 (vendored)
19│ │ ├── synthesizer.py # CTGAN 合成器
20│ │ ├── models.py # Generator/Discriminator 網路
21│ │ ├── transformer.py # 資料轉換器
22│ │ ├── conditional.py # 條件向量生成
23│ │ └── sampler.py # 訓練取樣器
24│ └── _ForestDiffusion/ # ForestDiffusion 核心實作 (vendored)
25│ └── diffusion_with_trees_class.py
26├── Research/ # 原始研究實驗
27│ ├── run_experiment.py # 基準實驗執行
28│ ├── run_check.py # 結果檢查
29│ └── data/ # 基準資料集 (8 個)
30├── examples/
31│ └── tabgan_examples.ipynb # Colab 範例筆記本
32├── tests/ # 完整測試套件 (14 個檔案)
33├── huggingface_space/ # HF Spaces Demo
34└── docs/ # Sphinx 文件
3. 安裝與設定 (Installation & Setup)
3.1 基本安裝
1# 使用 pip 安裝(最簡方式)
2pip install tabgan
3
4# 使用 uv 安裝(推薦,速度更快)
5uv pip install tabgan
3.2 開發環境安裝
1# Clone repo
2git clone https://github.com/Diyago/Tabular-data-generation.git
3cd Tabular-data-generation
4
5# 建立虛擬環境(推薦 uv)
6uv venv .venv --python 3.10
7source .venv/bin/activate
8
9# 安裝開發依賴
10uv pip install -e ".[dev]"
11
12# 或使用 requirements.txt
13uv pip install -r requirements.txt
3.3 可選依賴
1# ForestDiffusion 支援(擴散模型生成)
2uv pip install tabgan[diffusion]
3
4# LLM 支援(GReaT framework)
5uv pip install tabgan[llm]
6
7# 完整安裝(所有功能)
8uv pip install tabgan[all]
3.4 驗證安裝
1import tabgan
2print(tabgan.__version__)
3
4from tabgan.sampler import GANGenerator
5print("GANGenerator 載入成功")
3.5 環境需求
| 項目 | 需求 |
|---|---|
| Python | >= 3.8 |
| GPU | 可選(CTGAN 使用 PyTorch,有 GPU 更快) |
| RAM | >= 4 GB(視資料集大小而定) |
| 依賴 | pandas, numpy, scikit-learn, torch, lightgbm |
4. 使用方式與程式碼範例 (Usage & Code Examples)
範例 1:藥物開發資料增強 — CTGAN 合成 PK 參數
在臨床前研究中,動物實驗的 PK (Pharmacokinetics; 藥動學) 資料通常樣本量極小。使用 GAN 合成更多樣本,可增強下游統計分析的穩健性。
1import pandas as pd
2import numpy as np
3from tabgan.sampler import GANGenerator
4
5# 模擬臨床前 PK 資料(n=15,非常小的樣本量)
6np.random.seed(42)
7pk_data = pd.DataFrame({
8 "Cmax_ng_ml": np.random.lognormal(mean=3.5, sigma=0.6, size=15), # 最大血漿濃度
9 "Tmax_hr": np.random.uniform(0.5, 4.0, size=15), # 達峰時間
10 "AUC_0_inf": np.random.lognormal(mean=6.0, sigma=0.8, size=15), # 曲線下面積
11 "T_half_hr": np.random.lognormal(mean=2.0, sigma=0.4, size=15), # 半衰期
12 "CL_ml_min_kg": np.random.lognormal(mean=1.5, sigma=0.5, size=15), # 清除率
13 "Dose_Group": np.random.choice(["Low", "Mid", "High"], size=15), # 劑量組
14})
15
16# 療效指標作為目標變數
17efficacy = pd.DataFrame({
18 "Response": np.random.choice([0, 1], size=15, p=[0.7, 0.3]) # 30% 反應率
19})
20
21# 測試集(用於分佈對齊)
22pk_test = pd.DataFrame({
23 "Cmax_ng_ml": np.random.lognormal(mean=3.5, sigma=0.6, size=10),
24 "Tmax_hr": np.random.uniform(0.5, 4.0, size=10),
25 "AUC_0_inf": np.random.lognormal(mean=6.0, sigma=0.8, size=10),
26 "T_half_hr": np.random.lognormal(mean=2.0, sigma=0.4, size=10),
27 "CL_ml_min_kg": np.random.lognormal(mean=1.5, sigma=0.5, size=10),
28 "Dose_Group": np.random.choice(["Low", "Mid", "High"], size=10),
29})
30
31# 使用 GANGenerator 合成資料
32generator = GANGenerator(
33 gen_x_times=3.0, # 生成 3 倍原始資料量
34 cat_cols=["Dose_Group"], # 類別型欄位
35 bot_filter_quantile=0.001, # 下分位數過濾
36 top_filter_quantile=0.999, # 上分位數過濾
37 is_post_process=True, # 啟用後處理
38 pregeneration_frac=2, # 預生成倍率(生成更多再過濾)
39 only_generated_data=False, # 保留原始 + 合成
40 gen_params={
41 "batch_size": 500,
42 "patience": 25,
43 "epochs": 300,
44 },
45)
46
47# 執行生成管線
48augmented_pk, augmented_efficacy = generator.generate_data_pipe(
49 pk_data, efficacy, pk_test,
50 deep_copy=True,
51 use_adversarial=True, # 啟用對抗過濾
52)
53
54print(f"原始資料: {len(pk_data)} 筆")
55print(f"增強後資料: {len(augmented_pk)} 筆")
56print(f"\n合成資料統計:")
57print(augmented_pk.describe())
範例 2:AutoSynth 自動選擇最佳生成器 + 隱私評估
在合規場景下(如多中心臨床試驗資料共享),需要同時評估合成品質與隱私風險。AutoSynth 自動跑完所有 Generator,輸出綜合比較。
1import pandas as pd
2import numpy as np
3from tabgan import AutoSynth, PrivacyMetrics
4
5# 模擬臨床試驗患者資料
6np.random.seed(42)
7n_patients = 200
8clinical_data = pd.DataFrame({
9 "Age": np.random.normal(55, 12, n_patients).astype(int),
10 "BMI": np.random.normal(26, 4, n_patients).round(1),
11 "Tumor_Size_mm": np.random.lognormal(2.5, 0.8, n_patients).round(1),
12 "Biomarker_Level": np.random.lognormal(1.0, 1.2, n_patients).round(2),
13 "Stage": np.random.choice(["I", "II", "III", "IV"], n_patients, p=[0.3, 0.3, 0.25, 0.15]),
14 "Treatment": np.random.choice(["Drug_A", "Drug_B", "Placebo"], n_patients),
15 "Response": np.random.choice([0, 1], n_patients, p=[0.6, 0.4]),
16})
17
18# === AutoSynth: 自動比較所有 Generator ===
19result = AutoSynth(
20 clinical_data,
21 target_col="Response",
22 quality_weight=0.6, # 品質權重 60%
23 privacy_weight=0.4, # 隱私權重 40%
24).run()
25
26# 檢視比較報告
27print("=== AutoSynth 比較報告 ===")
28print(result.report)
29print(f"\n最佳 Generator: {result.best_name}")
30
31# 取得最佳合成資料
32best_synthetic = result.best_data
33
34# === 隱私指標詳細評估 ===
35pm = PrivacyMetrics(
36 clinical_data,
37 best_synthetic,
38 cat_cols=["Stage", "Treatment"],
39)
40summary = pm.summary()
41
42print(f"\n=== 隱私評估 ===")
43print(f"Overall Privacy Score: {summary['overall_privacy_score']:.3f}")
44print(f"DCR (Distance to Closest Record) 均值: {summary['dcr']['mean']:.4f}")
45print(f"NNDR (Nearest Neighbor Distance Ratio) 均值: {summary['nndr']['mean']:.4f}")
46print(f"Membership Inference AUC: {summary['membership_inference']['auc']:.3f}")
47print(f" (越接近 0.5 代表隱私保護越好)")
範例 3:sklearn Pipeline 整合 + 約束引擎應用於生物資料
將 TabGAN 嵌入 sklearn 機器學習管線,同時施加生物學上有意義的約束條件。
1import pandas as pd
2import numpy as np
3from sklearn.pipeline import Pipeline
4from sklearn.ensemble import GradientBoostingClassifier
5from sklearn.model_selection import cross_val_score
6from tabgan import TabGANTransformer, GANGenerator, RangeConstraint, FormulaConstraint
7
8# 模擬 scRNA-seq 衍生的細胞特徵資料
9np.random.seed(42)
10n_cells = 300
11X_train = pd.DataFrame({
12 "Gene_A_expr": np.random.lognormal(0, 1.5, n_cells).round(3), # 基因表達量 (>= 0)
13 "Gene_B_expr": np.random.lognormal(0, 1.2, n_cells).round(3),
14 "Cell_Size_um": np.random.normal(12, 3, n_cells).round(1), # 細胞大小 (um)
15 "Viability_pct": np.random.beta(8, 2, n_cells).round(3) * 100, # 存活率 (0-100%)
16 "Passage_Number": np.random.choice([3, 5, 7, 10], n_cells), # 代數
17 "Culture_Type": np.random.choice(["2D", "3D", "Organoid"], n_cells), # 培養方式
18})
19y_train = pd.Series(np.random.choice([0, 1], n_cells, p=[0.8, 0.2])) # 稀有表型
20
21# 定義生物學約束
22constraints = [
23 RangeConstraint("Gene_A_expr", min_val=0), # 基因表達量不可為負
24 RangeConstraint("Gene_B_expr", min_val=0),
25 RangeConstraint("Cell_Size_um", min_val=3, max_val=30), # 細胞大小合理範圍
26 RangeConstraint("Viability_pct", min_val=0, max_val=100),
27]
28
29# 建立 sklearn Pipeline:合成增強 → 分類
30pipeline_augmented = Pipeline([
31 ("augment", TabGANTransformer(
32 generator_class=GANGenerator,
33 gen_x_times=2.0, # 增強到 2 倍
34 cat_cols=["Culture_Type"],
35 gen_params={"batch_size": 500, "epochs": 100, "patience": 10},
36 constraints=constraints,
37 )),
38 ("model", GradientBoostingClassifier(
39 n_estimators=100,
40 random_state=42,
41 )),
42])
43
44# 無增強的基線 Pipeline
45pipeline_baseline = Pipeline([
46 ("model", GradientBoostingClassifier(
47 n_estimators=100,
48 random_state=42,
49 )),
50])
51
52# 比較效能
53scores_augmented = cross_val_score(
54 pipeline_augmented, X_train, y_train, cv=5, scoring="roc_auc"
55)
56scores_baseline = cross_val_score(
57 pipeline_baseline, X_train, y_train, cv=5, scoring="roc_auc"
58)
59
60print(f"基線 AUC: {scores_baseline.mean():.3f} +/- {scores_baseline.std():.3f}")
61print(f"增強 AUC: {scores_augmented.mean():.3f} +/- {scores_augmented.std():.3f}")
62print(f"改善幅度: {(scores_augmented.mean() - scores_baseline.mean()) * 100:.1f}%")
補充:CLI 快速生成
1# 命令列一行完成合成
2tabgan-generate \
3 --input-csv preclinical_pk_data.csv \
4 --target-col Response \
5 --generator gan \
6 --gen-x-times 2.0 \
7 --cat-cols Dose_Group,Treatment_Arm \
8 --output-csv synthetic_pk_data.csv
5. 在 SDG 生態系中的定位 (Position in the SDG Ecosystem)
5.1 技術世代定位
TabGAN 是 Domain 3「通用 SDG 框架與評估」中少數橫跨三個世代的專案:
1SDG 技術演進時間軸:
2
32018 ─── 2020 ─── 2022 ─── 2024 ─── 2026
4 │ │ │ │ │
5 CTGAN TabGAN TabDDPM GReaT TabGAN v3
6 (原始) (v1.0) (擴散) (LLM) (統一三代)
7 │ │ │ │ │
8 ├────── GAN 世代 ──┤ │ │
9 │ ├── Diffusion 世代 ┤
10 │ │ ├── LLM 世代 ──┤
11 │ │ │ │
12 └──────── TabGAN 從 GAN 起步,逐步整合 ────┘
5.2 與 Domain 3 其他專案的比較
| 面向 | TabGAN | SDV | synthcity | CTGAN (sdv) | TabDDPM |
|---|---|---|---|---|---|
| 定位 | 實務教學+統一介面 | 完整平台 | 研究框架 | 單一 Generator | 純研究 |
| Generator 種類 | 5 種 | 10+ 種 | 15+ 種 | 1 種 | 1 種 |
| 對抗過濾 | 內建 | 無 | 無 | 無 | 無 |
| 隱私評估 | 內建 | 透過 SDMetrics | 內建 | 無 | 無 |
| AutoSynth | 內建 | 無 | 有 (benchmark) | 無 | 無 |
| sklearn 整合 | 原生 | 無 | 有限 | 無 | 無 |
| 學習曲線 | 低 | 中 | 高 | 最低 | 高 |
| 適用場景 | 快速原型+生產 | 企業級 | 學術研究 | 入門學習 | 論文復現 |
5.3 在 Bio-SDG 生態系中的角色
在 Bio-SDG 7 大 Domain 的版圖中,TabGAN 屬於 Domain 3 的實務橋樑 (Practical Bridge):
- 上游整合:接收 Domain 1 (醫療 SDG) 的需求,如臨床表格資料增強
- 技術銜接:統一封裝 Domain 3 的三種核心技術(GAN/Diffusion/LLM)
- 下游輸出:生成的合成資料可供 Domain 3 的評估工具(SDMetrics)驗證
- 藥廠適用:內建隱私指標,符合 FDA 對合成資料的合規期待
5.4 對 AIKT WP1-WP7 管線的價值
| AIKT 工作包 | TabGAN 可貢獻之處 |
|---|---|
| WP1 (資料收集) | HuggingFace Hub 整合,一行抓取公開表格資料集 |
| WP2 (資料處理) | Constraint Engine 施加生物學約束 |
| WP3 (特徵工程) | 合成資料增強稀有表型類別 |
| WP4 (模型訓練) | sklearn Pipeline 直接嵌入 ML 管線 |
| WP5 (評估驗證) | AutoSynth + PrivacyMetrics 自動化品質/隱私評估 |
| WP6 (部署) | CLI 工具 + PyPI 套件,可直接整合至 CI/CD |
6. 與其他工具的整合 (Integration with Other SDG Tools)
6.1 與 SDV / SDMetrics 的互補
TabGAN 與 SDV 生態系並非競爭關係,而是互補:
1# TabGAN 生成 → SDMetrics 評估
2from tabgan.sampler import GANGenerator
3from sdmetrics.reports.single_table import QualityReport
4
5# Step 1: 用 TabGAN 生成
6gen = GANGenerator(gen_x_times=1.5, cat_cols=["Stage"])
7synthetic, _ = gen.generate_data_pipe(train, target, test)
8
9# Step 2: 用 SDMetrics 做更深度的評估
10report = QualityReport()
11report.generate(real_data=train, synthetic_data=synthetic, metadata=metadata)
12print(report.get_score())
6.2 與 ForestDiffusion 的原生整合
TabGAN 已 vendor(內嵌)ForestDiffusion 原始碼,可直接使用:
1from tabgan.sampler import ForestDiffusionGenerator
2
3# 無需額外安裝 ForestDiffusion
4gen = ForestDiffusionGenerator(gen_x_times=2.0)
5synthetic, target = gen.generate_data_pipe(train, target, test)
6.3 與 LLM 生態系的整合
支援多種 LLM 後端,包含本地部署與雲端 API:
1from tabgan.sampler import LLMGenerator
2from tabgan.llm_config import LLMAPIConfig
3
4# 本地 LM Studio(隱私資料不出機器)
5config = LLMAPIConfig.from_lm_studio(
6 base_url="http://localhost:1234",
7 model="google/gemma-3-12b",
8)
9
10# 或 Ollama(本地部署)
11config = LLMAPIConfig.from_ollama(model="llama3")
12
13# 或 OpenAI API
14config = LLMAPIConfig.from_openai(api_key="...", model="gpt-4")
15
16gen = LLMGenerator(
17 gen_x_times=1.5,
18 llm_api_config=config,
19 gen_params={"batch_size": 32, "epochs": 4},
20)
6.4 與 HuggingFace Hub 的整合
1from tabgan import synthesize_hf_dataset
2
3# 一行合成 HF 上的任何表格資料集
4result = synthesize_hf_dataset(
5 "scikit-learn/iris",
6 target_col="target",
7 push_to_hub=True,
8 hub_repo_id="your-org/iris-synthetic",
9)
10print(f"品質分數: {result.quality_summary['overall_score']}")
6.5 與 Domain 3 其他專案的串接建議
| 串接場景 | 工具組合 | 說明 |
|---|---|---|
| 快速比較 GAN vs Diffusion | TabGAN AutoSynth | 內建,無需外部工具 |
| 深度品質評估 | TabGAN + SDMetrics | TabGAN 生成,SDMetrics 評估 |
| 生產級管線 | TabGAN + synthcity benchmark | synthcity 做更嚴格的 benchmark |
| 隱私合規 | TabGAN PrivacyMetrics + dp_cgans | DP 版本用 dp_cgans,評估用 TabGAN |
| 學術論文 | TabGAN + STDG-evaluation-metrics | 標準化評估指標報告 |
7. 優缺點分析 (Strengths & Limitations)
優點 (Strengths)
| 面向 | 說明 |
|---|---|
| 統一介面 | 五種 Generator 共用 generate_data_pipe(),切換成本極低 |
| 對抗過濾 | LightGBM-based adversarial filter 是獨特賣點,有效提升分佈忠實度 |
| 端到端品質把控 | 生成 → 後處理 → 過濾 → 隱私評估,單一套件覆蓋全流程 |
| sklearn 原生整合 | TabGANTransformer 可直接嵌入既有 ML Pipeline,無需改架構 |
| AutoSynth | 自動化 Generator 比較,降低選擇障礙 |
| Constraint Engine | 可施加領域知識約束(Range/Unique/Formula/Regex),對生醫場景特別有用 |
| 隱私指標 | DCR/NNDR/MI 三重評估,合規場景可直接引用 |
| 學習資源 | 原始 Research/ 資料夾保留完整實驗程式碼,配合論文可深入理解 |
| 活躍維護 | 持續整合 Diffusion 與 LLM 新技術,2026 年仍在更新 |
限制 (Limitations)
| 面向 | 說明 | 替代方案 |
|---|---|---|
| 規模限制 | 主要設計給中小型表格(< 100K rows),超大規模效能未優化 | SDV / synthcity |
| 無時間序列 | 不支援 Sequential / Time-series 資料生成 | SDV TimeGAN / synthcity |
| 無關聯表格 | 不支援多表格關聯(PK-FK)生成 | SDV Multi-Table |
| 無差分隱私 | 隱私「評估」有但「保證」無(非 DP-GAN) | dp_cgans / PATE-GAN |
| CTGAN 核心限制 | vendored 的 CTGAN 是較舊版本,某些 edge case 可能不如 sdv-dev/CTGAN 穩定 | sdv-dev/CTGAN |
| 文件深度 | API 文件完整但缺乏進階教學(如超參調校指南) | synthcity 教學 |
| 無影像/文本 | 純表格工具,不處理非結構化資料 | Domain 2 工具 |
對藥廠使用者的具體建議
1適用場景:
2 ✅ 臨床前 PK/PD 小樣本增強(n < 100)
3 ✅ 臨床試驗患者表格的合成資料共享
4 ✅ scRNA-seq 衍生特徵表的類別平衡
5 ✅ ML 管線中的資料增強(sklearn Pipeline 嵌入)
6 ✅ 快速比較 GAN vs Diffusion vs LLM 生成品質
7
8不適用場景:
9 ❌ 需要數學上保證差分隱私 (Differential Privacy) 的場景
10 ❌ 多表格關聯資料(如 EHR 中的患者-就診-處方多表)
11 ❌ 時間序列資料(如連續監測的生命徵象)
12 ❌ 影像或基因體序列等非結構化資料
Blue Ocean 機會
從 TabGAN 的設計缺口中,可辨識出 SDG 領域的幾個未被滿足的需求:
- DP + Adversarial Filter 結合 — TabGAN 的對抗過濾 + dp_cgans 的差分隱私,尚無現成工具整合兩者
- 生物學約束的自動推論 — 目前約束需手動定義,從 ontology (本體論) 自動推導約束是開放問題
- 多模態表格生成 — 同時生成數值/類別/文本/影像連結的合成記錄
- FDA 合規報告 — 自動生成符合 FDA Synthetic Data Guidance 的驗證報告
本教學為 Bio-SDG 生態系探索 Domain 3「通用 SDG 框架與評估」系列的一部分。 撰寫日期:2026-06-10
Comments