2  Part 2:Table 1 — Baseline characteristics

預計時間:20 分鐘。 deliverable:一張 Table 1,看起來像投到 Ophthalmology 的版本。

我有一個 R data frame baseline,欄位包括:patient_id, arm (faricimab/aflibercept), study, region, age, sex, bcva_baseline, cst_baseline, irf_baseline, srf_baseline, bcva_strat, lld_strat。請用 gtsummary::tbl_summary() 做一個 Table 1:

  1. by arm 分兩欄
  2. 連續變項顯示 mean (SD)
  3. 二元變項 irf_baseline / srf_baseline 顯示 n (%)
  4. 加 add_overall() 多一欄總計
  5. 加 add_p() 顯示組間檢定 p value
  6. 把欄位名稱改成 paper 風格的英文 label

請給我可以直接貼到 RStudio Console 跑的 code,加中文註解。


📖 名詞|ETDRS letters / mean (SD) / n (%)
  • ETDRS letters = 國際標準視力表1,每行 5 letter,看清楚一行 = 5 letter;總分 0–100。+5 letter ≈ 視力「進步一行」
  • mean (SD) = 平均 (標準差),連續變項的 paper 標準寫法。SD 大 = 個體差異大
  • n (%) = 人數 (百分比),類別變項標準寫法
📚 Table 1 / SMD 方法學引用
  • RCT 的 Table 1 用來描述基線、不應強調 p value(隨機分派下差異是 chance);RWE / 觀察性研究則用 standardized mean difference (SMD/ASMD) > 0.1 標示需要 adjust 的混淆因子,這是 propensity score 領域的標準2,3
  • 多重 prognostic factor 的調整原則參考 Kahan & Morris 20134、Agoritsas 2017 JAMA Users’ Guide5

2.1 任務 6:第一張 Table 1

📋 複製這段話,貼給 AI(🆕 開新對話):

請用 R 套件 gtsummarytbl_summary() 做一張 Table 1,by arm 分組,包含這些變項:age, sex, region, bcva_baseline, cst_baseline, irf_baseline, srf_baseline, study, bcva_strat, lld_strat。連續變項顯示 mean (SD),二元 irf_baseline 和 srf_baseline 顯示 n (%)。

2.1.1 參考程式碼

# ── 前置(可單獨執行):套件 + 資料 ──
library(readr); library(dplyr); library(gtsummary); library(gt)
baseline <- read_csv("data/faricimab_baseline.csv", show_col_types = FALSE)
t1_basic <- baseline |>
  select(arm, age, sex, region, bcva_baseline, cst_baseline,
         irf_baseline, srf_baseline, study, bcva_strat, lld_strat) |>
  tbl_summary(
    by = arm,
    type = list(
      age ~ "continuous",
      bcva_baseline ~ "continuous",
      cst_baseline ~ "continuous",
      irf_baseline ~ "dichotomous",
      srf_baseline ~ "dichotomous"
    ),
    statistic = list(
      all_continuous() ~ "{mean} ({sd})",
      all_categorical() ~ "{n} ({p}%)"
    ),
    digits = list(
      all_continuous() ~ 1,
      all_categorical() ~ c(0, 1)
    ),
    label = list(
      age ~ "Age, years",
      sex ~ "Sex",
      region ~ "Region",
      bcva_baseline ~ "BCVA at baseline, ETDRS letters",
      cst_baseline ~ "CST at baseline, μm",
      irf_baseline ~ "IRF present at baseline",
      srf_baseline ~ "SRF present at baseline",
      study ~ "Study",
      bcva_strat ~ "BCVA stratum",
      lld_strat ~ "LLD stratum"
    )
  )

t1_basic
Characteristic aflibercept
N = 6641
faricimab
N = 6651
Age, years 75.1 (9.0) 75.3 (9.2)
Sex

    F 380 (57.2%) 380 (57.1%)
    M 284 (42.8%) 285 (42.9%)
Region

    Rest-of-world 295 (44.4%) 294 (44.2%)
    US-Canada 369 (55.6%) 371 (55.8%)
BCVA at baseline, ETDRS letters 60.1 (13.1) 58.9 (13.3)
CST at baseline, μm 371.2 (111.5) 363.4 (111.5)
IRF present at baseline 317 (47.7%) 284 (42.7%)
SRF present at baseline 441 (66.4%) 441 (66.3%)
Study

    LUCERNE 320 (48.2%) 348 (52.3%)
    TENAYA 344 (51.8%) 317 (47.7%)
BCVA stratum

    <=54 224 (33.7%) 250 (37.6%)
    >=74 99 (14.9%) 77 (11.6%)
    55-73 341 (51.4%) 338 (50.8%)
LLD stratum

    <33 438 (66.0%) 452 (68.0%)
    >=33 226 (34.0%) 213 (32.0%)
1 Mean (SD); n (%)
🎯 對得起 paper 嗎?

看 BCVA 那一列:兩臂應該都接近 60.0 (SD ~13); CST 兩臂都接近 357 (SD ~120)。 如果差很多,回去檢查模擬資料 — 但你應該不會差。


2.2 任務 7:加 overall 與 p value

📋 複製這段話,貼給 AI(↩︎️ 續前對話):

在剛剛那張 Table 1 上加: 1. add_overall() 多一欄「Total」 2. add_p() 顯示兩臂之間的差異檢定 p value 3. 把 footer 改成繁體中文「連續變項:mean (SD);類別變項:n (%);組間檢定為 t-test 或 χ²」

2.2.1 參考程式碼

# ── 前置(可單獨執行):套件 + 資料 ──
library(readr); library(dplyr); library(gtsummary); library(gt)
baseline <- read_csv("data/faricimab_baseline.csv", show_col_types = FALSE)
# ⚠️ 沿用前面任務的物件:t1_basic(請先跑完任務6,本段不重算)
t1 <- t1_basic |>
  add_overall() |>
  add_p() |>
  modify_footnote(
    update = all_stat_cols() ~ "連續變項:mean (SD);類別變項:n (%)"
  ) |>
  modify_caption("**Table 1.** Baseline characteristics by treatment arm")

t1
Table 1. Baseline characteristics by treatment arm
Characteristic Overall
N = 1,3291
aflibercept
N = 6641
faricimab
N = 6651
p-value2
Age, years 75.2 (9.1) 75.1 (9.0) 75.3 (9.2) >0.9
Sex


>0.9
    F 760 (57.2%) 380 (57.2%) 380 (57.1%)
    M 569 (42.8%) 284 (42.8%) 285 (42.9%)
Region


>0.9
    Rest-of-world 589 (44.3%) 295 (44.4%) 294 (44.2%)
    US-Canada 740 (55.7%) 369 (55.6%) 371 (55.8%)
BCVA at baseline, ETDRS letters 59.5 (13.2) 60.1 (13.1) 58.9 (13.3) 0.2
CST at baseline, μm 367.3 (111.5) 371.2 (111.5) 363.4 (111.5) 0.2
IRF present at baseline 601 (45.2%) 317 (47.7%) 284 (42.7%) 0.065
SRF present at baseline 882 (66.4%) 441 (66.4%) 441 (66.3%) >0.9
Study


0.13
    LUCERNE 668 (50.3%) 320 (48.2%) 348 (52.3%)
    TENAYA 661 (49.7%) 344 (51.8%) 317 (47.7%)
BCVA stratum


0.12
    <=54 474 (35.7%) 224 (33.7%) 250 (37.6%)
    >=74 176 (13.2%) 99 (14.9%) 77 (11.6%)
    55-73 679 (51.1%) 341 (51.4%) 338 (50.8%)
LLD stratum


0.4
    <33 890 (67.0%) 438 (66.0%) 452 (68.0%)
    >=33 439 (33.0%) 226 (34.0%) 213 (32.0%)
1 連續變項:mean (SD);類別變項:n (%)
2 Wilcoxon rank sum test; Pearson’s Chi-squared test
如何讀 p value

這是 RCT,所有 baseline 變項的 p 都應該不顯著(p > 0.05)—— 因為隨機分派應該讓兩組平衡。 如果你以後做 RWE 看到某些 baseline 變項 p < 0.05,那是「兩組基線不平衡」,要在 model 裡 adjust。


2.3 任務 8:存成檔案

📋 複製這段話,貼給 AI(↩︎️ 續前對話):

請告訴我怎麼把這張 gtsummary table 存成 (a) html (b) docx,給共同作者看。

2.3.1 參考程式碼

# ── 前置(可單獨執行):套件 + 資料 ──
library(readr); library(dplyr); library(gtsummary); library(gt); library(flextable)
baseline <- read_csv("data/faricimab_baseline.csv", show_col_types = FALSE)
# ⚠️ 沿用前面任務的物件:t1(請先跑完任務6、7,本段不重算)
# 存 HTML(瀏覽器打開)
t1 |>
  as_gt() |>
  gt::gtsave(filename = "table1.html")

# 存 Word docx(要先裝 gt 的最新版)
t1 |>
  as_flex_table() |>
  flextable::save_as_docx(path = "table1.docx")

2.4 任務 9:怎麼讀 Table 1 判斷「兩組是否平衡」

📋 複製這段話,貼給 AI(🆕 開新對話):

在 RCT paper 裡,Table 1 通常用來說明兩組基線特性平衡。請用繁體中文告訴我: 1. 看哪些 row? 2. 為什麼大部分 RCT 的 Table 1 不會放 p value(or 放但不強調)? 3. 如果是 RWE,Table 1 該放什麼?標準化差異(SMD)是什麼?

速記
  • RCT:Table 1 是 descriptive,p value 是 ritual(隨機分派理論上組間差異是 chance)
  • RWE / observational:Table 1 用來找需要 adjust 的 confounder,看 SMD > 0.1 的變項
  • gtsummary::add_difference()tableone::CreateTableOne() 可以加 SMD
📖 名詞|SMD(standardized mean difference)

標準化均差。RCT 用 p value 看 baseline 平衡夠不夠,但 RWE 沒有隨機分派,SMD 是 paper reviewer 比較買單的指標2: SMD 把「兩組差距」除以「合併標準差」,這樣不同單位(年齡 vs 視力 letters)也能比較。 SMD > 0.1 通常被認為「值得 adjust」2,3


本章重點
  1. gtsummary::tbl_summary() 一行寫完論文等級的 Table 1
  2. by = arm 自動分欄
  3. RCT 的 Table 1 看「兩組差不多」就好;RWE 看 SMD
  4. as_gt() 之後可存 html/docx,丟給共同作者
1.
Ferris FL, Kassoff A, Bresnick GH, Bailey I. New visual acuity charts for clinical research. American Journal of Ophthalmology. 1982;94(1):91-96. doi:10.1016/0002-9394(82)90197-0
2.
Austin PC. Balance diagnostics for comparing the distribution of baseline covariates between treatment groups in propensity-score matched samples. Statistics in Medicine. 2009;28(25):3083-3107. doi:10.1002/sim.3697
3.
Austin PC. An introduction to propensity score methods for reducing the effects of confounding in observational studies. Multivariate Behavioral Research. 2011;46(3):399-424. doi:10.1080/00273171.2011.568786
4.
Kahan BC, Morris TP. Adjusting for multiple prognostic factors in the analysis of randomised trials. BMC Medical Research Methodology. 2013;13:99. doi:10.1186/1471-2288-13-99
5.
Agoritsas T, Merglen A, Shah ND, O’Donnell M, Guyatt GH. Adjusted analyses in studies addressing therapy and harm: Users’ guides to the medical literature. JAMA. 2017;317(7):748-759. doi:10.1001/jama.2016.20029