R包table1創(chuàng)建網(wǎng)頁格式的描述性統(tǒng)計表Table 1

  • 介紹
  • 例1
  • 例2
  • 使用縮寫代碼指定自定義renderer
  • 顯示不同變量的不同統(tǒng)計信息
  • 改變表的外觀 - 使用內(nèi)置的樣式
  • p-values列
  • 表格的轉(zhuǎn)置

介紹

在流行病學(xué)和其相關(guān)領(lǐng)域期刊上的標(biāo)準(zhǔn)做法是,用第一個表格(即Table 1)展示按暴露程度分層的研究人群的基線特征的描述性統(tǒng)計。使用R包table1去生成Table 1相當(dāng)?shù)膃asy。輸出格式為HTML,其優(yōu)點是易于復(fù)制到Word文檔中。這個包允許相當(dāng)大的靈活性來定制表的內(nèi)容和外觀,但是這需要更多的編程和CSS知識。

例1

使用boot包中的melanoma數(shù)據(jù)集來進行展示,數(shù)據(jù)集的變量定義和具體描述利用?melanoma進行查看,melanoma數(shù)據(jù)框有205行,7列。

數(shù)據(jù)集介紹
library(table1) 
library(boot) 
melanoma2 <- melanoma
 
# Factor the basic variables that
# we're interested in
melanoma2$status <- 
  factor(melanoma2$status, 
         levels=c(2,1,3),
         labels=c("Alive", # Reference
        "Melanoma death", 
        "Non-melanoma death"))

先來個簡單的操作試試感覺:

table1(~ factor(sex) + age + factor(ulcer) + thickness | status, data=melanoma2)

注意,table1包使用了一個熟悉的公式接口,各變量之間用 + 分隔,條件符號 | 的右邊為分層變量,參數(shù)data指定使用的數(shù)據(jù)集。

變量和分類的標(biāo)簽可能不適合用來描述結(jié)果,可以給分類變量指定標(biāo)簽,給特定的連續(xù)變量指定單位。


melanoma2$sex <-   factor(melanoma2$sex, levels=c(1,0),  labels=c("Male", "Female")) 
melanoma2$ulcer <- factor(melanoma2$ulcer, levels=c(0,1),  labels=c("Absent",  "Present"))

label(melanoma2$sex)       <- "Sex"
label(melanoma2$age)       <- "Age"
label(melanoma2$ulcer)     <- "Ulceration"
label(melanoma2$thickness) <- "Thickness"

units(melanoma2$age)       <- "years"
units(melanoma2$thickness) <- "mm"

table1(~ sex + age + ulcer + thickness | status, data=melanoma2, overall="Total")

這看起來好了很多,但是還可以做一些調(diào)整,如:調(diào)整Total列至最左側(cè)、兩個“Death”層(Melanoma Death和Non-melanoma Death)應(yīng)該在一個共同的標(biāo)題下分組、修改連續(xù)變量(Age和Thickness)的展示形式 Means (SD)為 Means (± SD)、不輸出默認(rèn)的Median [Min, Max] 統(tǒng)計量、有效數(shù)字的修改等。這稍微有些復(fù)雜,一般的操作可以修改示例中定義的函數(shù)來實現(xiàn)。

首先,利用list來設(shè)置我們的標(biāo)簽:


labels <- list(
    variables=list(sex="Sex",
                   age="Age (years)",
                   ulcer="Ulceration",
                   thickness="Thickness (mm)"),
    groups=list("", "", "Death"))

# Remove the word "death" from the labels, since it now appears above
levels(melanoma2$status) <- c("Alive", "Melanoma", "Non-melanoma")

然后,按照我們想要展示的順序設(shè)置層或列為data.frame的列表:

strata <- c(list(Total=melanoma2), split(melanoma2, melanoma2$status))

最后,我們可以使用自定義的renderers來定制表的內(nèi)容。renderers可以是一個函數(shù),它以一個向量作為第一個參數(shù)并返回一個(命名的)字符向量。還有一種更簡單的方法來定制表內(nèi)容,使用簡短的代碼語法而不是render函數(shù)。例如,在這里,我們?yōu)檫B續(xù)變量和分類變量指定render函數(shù),如下所示:

my.render.cont <- function(x) {
    with(stats.apply.rounding(stats.default(x), digits=2), c("",
"Mean (SD)"=sprintf("%s (&plusmn; %s)", MEAN, SD)))
}
my.render.cat <- function(x) {
    c("", sapply(stats.default(x), function(y) with(y,
        sprintf("%d (%0.0f %%)", FREQ, PCT))))
}

結(jié)果展示如下:

table1(strata, labels, groupspan=c(1, 1, 2),
       render.continuous=my.render.cont, render.categorical=my.render.cat)

例2

例2中使用模擬數(shù)據(jù)。我們設(shè)想一個臨床試驗,受試者被隨機以2:1的比例接受積極治療或安慰劑。為了簡單起見,只考慮三個基本特征:年齡、性別和體重。

f <- function(x, n, ...) factor(sample(x, n, replace=T, ...), levels=x)
set.seed(427)

n <- 146
dat <- data.frame(id=1:n)
dat$treat <- f(c("Placebo", "Treated"), n, prob=c(1, 2)) # 2:1 randomization
dat$age   <- sample(18:65, n, replace=TRUE)
dat$sex   <- f(c("Female", "Male"), n, prob=c(.6, .4))  # 60% female
dat$wt    <- round(exp(rnorm(n, log(70), 0.23)), 1)

# Add some missing data
dat$wt[sample.int(n, 5)] <- NA

label(dat$age)   <- "Age"
label(dat$sex)   <- "Sex"
label(dat$wt)    <- "Weight"
label(dat$treat) <- "Treatment Group"

units(dat$age)   <- "years"
units(dat$wt)    <- "kg"

先來看看默認(rèn)設(shè)置下得到的表格長什么樣子:

table1(~ age + sex + wt | treat, data=dat)

請注意,當(dāng)包含缺失值(這里的weight變量)時,無論是連續(xù)還是分類變量,都將報告一個不同的類別Missing (帶有計數(shù)和百分比)。

“Overall” 這一列可以輕松的去掉或者重新給標(biāo)簽:

table1(~ age + sex + wt | treat, data=dat, overall=F)

我們還可以通過兩個變量進行分層,在這種情況下,它們是嵌套的。例如,將每個治療組按性別劃分:

table1(~ age + wt | treat*sex, data=dat)

或者,調(diào)換一下順序,按照性別分別劃分治療情況:

table1(~ age + wt | sex*treat, data=dat)

或者,直接不分層展示(即展示總的統(tǒng)計情況):

table1(~ treat + age + sex + wt, data=dat)

最后,我們可能會再次考慮一些更復(fù)雜的東西,使用默認(rèn)(即non-formula)接口。假設(shè)不是簡單地分配給安慰劑或積極治療,實際上有兩種隨機的治療劑量,5毫克和10毫克,我們希望單獨列出每個劑量水平,以及所有接受治療的受試者。

dat$dose <- (dat$treat != "Placebo")*sample(1:2, n, replace=T)
dat$dose <- factor(dat$dose, labels=c("Placebo", "5 mg", "10 mg"))

strata <- c(split(dat, dat$dose), list("All treated"=subset(dat, treat=="Treated")), list(Overall=dat))

labels <- list(
    variables=list(age=render.varlabel(dat$age),
                   sex=render.varlabel(dat$sex),
                   wt=render.varlabel(dat$wt)),
    groups=list("", "Treated", ""))

table1(strata, labels, groupspan=c(1, 3, 1))

使用縮寫代碼指定自定義renderer

假設(shè)對于連續(xù)變量,我們想要顯示百分比變異系數(shù)(CV%)而不是標(biāo)準(zhǔn)差(SD)。我們還想顯示幾何平均值和幾何變異系數(shù)。我們已經(jīng)討論了可用于完成此任務(wù)的自定義render函數(shù),但是更簡單的替代方法是使用縮寫代碼。這是一個包含某些關(guān)鍵字的字符串,這些關(guān)鍵字被替換為表輸出中的計算值。識別關(guān)鍵字列表來自于stats.default函數(shù)的輸出,包括:N, NMISS, MEAN, SD, CV, GMEAN, GCV, MEDIAN, MIN, MAX, IQR, Q1, Q2, Q3, T1, T2, FREQ, PCT。關(guān)鍵字匹配不區(qū)分大小寫,除了關(guān)鍵字之外的任何文本都保持原樣。我們可以指定一個字符串向量,在這種情況下,每個結(jié)果都將顯示在表的行中。我們可以使用一個命名向量為每一行指定標(biāo)簽,點號(‘.’)可用于指示將縮寫的代碼字符串本身用作行標(biāo)簽。有效數(shù)字可以使用digits參數(shù)(默認(rèn)值: 3)進行控制。以下是上一節(jié)示例的后續(xù),該示例生成了所需的結(jié)果:

table1(strata, labels, groupspan=c(1, 3, 1),
       render.continuous=c(.="Mean (CV%)", 
                           .="Median [Min, Max]",
      "Geo. mean (Geo. CV%)"="GMEAN (GCV%)"))

顯示不同變量的不同統(tǒng)計信息

假設(shè)需要顯示年齡的中位數(shù)和極差,而顯示體重的平均值和標(biāo)準(zhǔn)差。這可以使用自定義的render函數(shù)實現(xiàn):

rndr <- function(x, name, ...) {
if (!is.numeric(x)) return(render.categorical.default(x))
    what <- switch(name,
        age = "Median [Min, Max]",
        wt  = "Mean (SD)")
    parse.abbrev.render.code(c("", what))(x)
}

table1(~ age + sex + wt | treat, data=dat,
       render=rndr)

注意,除了分別重寫render.continuousrender.categorical,也可以重寫 render 來同時處理這兩種情況。render函數(shù)獲取變量的名稱作為它的第二個參數(shù),并且還應(yīng)該接受...來獲取傳遞給它的任何其他參數(shù)。還要注意函數(shù)parse.abbrev.render.code可用于將縮寫代碼轉(zhuǎn)換為相應(yīng)的render函數(shù)。

改變表的外觀

table1的默認(rèn)樣式使用Arial字體,類似于LaTeX中常用的 booktabs樣式。雖然這種默認(rèn)樣式并不難看,但不可避免地會希望定制表的視覺外觀(字體、顏色、網(wǎng)格線等)。該包提供了有限數(shù)量的內(nèi)置選項來更改樣式,而進一步的定制可以在使用CSS的R R Markdown文檔中實現(xiàn)(不展示)。

使用內(nèi)置的樣式

該package包括有限數(shù)量的內(nèi)置樣式,包括:

  • zebra: 交替的陰影行和非陰影行(斑馬條紋)
  • grid: 顯示所有網(wǎng)格線
  • shade: 將標(biāo)題行涂成灰色
  • times: 使用serif字體
  • center: 將所有列居中,包括第一列(行標(biāo)簽列)

可以使用table1topclass參數(shù)選擇這些樣式。一些例子:

table1(~ age + sex + wt | treat, data=dat, topclass="Rtable1-zebra")
table1(~ age + sex + wt | treat, data=dat, topclass="Rtable1-grid")
table1(~ age + sex + wt | treat, data=dat, topclass="Rtable1-grid Rtable1-shade Rtable1-times")

注意,樣式名前面需要加上前綴Rtable1-。通過使用空格分隔多個樣式,可以組合應(yīng)用多個樣式。

p-values列

顯示與單變量檢驗相關(guān)的p值,以檢驗各變量在不同層中的差異。目前包中還沒有內(nèi)置實現(xiàn)這一點的工具,但是使用自定義render函數(shù)和空層,可以“欺騙”它來生成所需的結(jié)果。下面的示例使用來自MatchIt包的lalonde數(shù)據(jù)。在本例中,分類變量使用獨立卡方檢驗,連續(xù)變量使用t檢驗(如果需要,還可以使用其他檢驗)。

library(MatchIt) 
## Warning: package 'MatchIt' was built under R version 3.5.3
data(lalonde)

lalonde$treat    <- factor(lalonde$treat, levels=c(0, 1, 2), labels=c("Control", "Treatment", "P-value"))
lalonde$black    <- factor(lalonde$black)
lalonde$hispan   <- factor(lalonde$hispan)
lalonde$married  <- factor(lalonde$married)
lalonde$nodegree <- factor(lalonde$nodegree)
lalonde$black    <- as.logical(lalonde$black == 1)
lalonde$hispan   <- as.logical(lalonde$hispan == 1)
lalonde$married  <- as.logical(lalonde$married == 1)
lalonde$nodegree <- as.logical(lalonde$nodegree == 1)

label(lalonde$black)    <- "Black"
label(lalonde$hispan)   <- "Hispanic"
label(lalonde$married)  <- "Married"
label(lalonde$nodegree) <- "No high school diploma"
label(lalonde$age)      <- "Age"
label(lalonde$re74)     <- "1974 Income"
label(lalonde$re75)     <- "1975 Income"
label(lalonde$re78)     <- "1978 Income"
units(lalonde$age)      <- "years"

rndr <- function(x, name, ...) {
if (length(x) == 0) {
        y <- lalonde[[name]]
        s <- rep("", length(render.default(x=y, name=name, ...)))
if (is.numeric(y)) {
            p <- t.test(y ~ lalonde$treat)$p.value
        } else {
            p <- chisq.test(table(y, droplevels(lalonde$treat)))$p.value
        }
        s[2] <- sub("<", "&lt;", format.pval(p, digits=3, eps=0.001))
        s
    } else {
        render.default(x=x, name=name, ...)
    }
}

rndr.strat <- function(label, n, ...) {
    ifelse(n==0, label, render.strat.default(label, n, ...))
}

table1(~ age + black + hispan + married + nodegree + re74 + re75 + re78 | treat,
    data=lalonde, droplevels=F, render=rndr, render.strat=rndr.strat, overall=F)

誠然,這不是很優(yōu)雅,但是它仍然很好地說明了這個包的靈活性,因為它能夠完成我們從未真正計劃過的事情。

表格的轉(zhuǎn)置

默認(rèn)情況下,table1生成的表將以層或亞組為列,以變量為行。在某些情況下,可能需要對表進行轉(zhuǎn)置,使每一列都是變量,行是層。當(dāng)所有的變量都是連續(xù)的,并且需要一個緊湊的表示形式時,這是最有意義的。它可以通過使用transpose = TRUE選項來實現(xiàn)。

一個例子:

dat <- expand.grid(i=1:50, group=LETTERS[1:3])
dat <- cbind(dat, matrix(round(exp(rnorm(6*nrow(dat))), 1), nrow=nrow(dat)))
names(dat)[3:8] <- paste0("V", 1:6)

默認(rèn):

table1(~ V1 + V2 + V3 + V4 + V5 + V6 | group, data=dat,
       topclass="Rtable1-grid Rtable1-center",
       render="Mean (CV%)<br/>Median [Min, Max]<br/>GMean (GCV%)")

轉(zhuǎn)置:

table1(~ V1 + V2 + V3 + V4 + V5 + V6 | group, data=dat,
       topclass="Rtable1-grid Rtable1-center",
       render="Mean (CV%)<br/>Median [Min, Max]<br/>GMean (GCV%)",
       transpose=TRUE)
image

參考閱讀:
https://cran.r-project.org/web/packages/table1/vignettes/table1-examples.html
https://stackoverflow.com/questions/54945344/p-value-column-in-table1-using-table1-function
https://cran.r-project.org/web/packages/table1/table1.pdf
https://cran.r-project.org/web/packages/furniture/vignettes/Table1.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容