R:如何旋转和计数 data.frame(例如:医疗状况列表和每种情况的患者人数)

R: How to pivot and count data.frame (ex: list of medical conditions and the number of patients with each)

我正在尝试使用 dplyr 和 tidyr 变得更好,但我不习惯 "thinking in R"。一个例子可能是最好的。我从 sql 中的数据生成的 table 如下所示:

╔═══════════╦════════════╦═════╦════════╦══════════════╦══════════╦══════════════╗
║ patientid ║ had_stroke ║ age ║ gender ║ hypertension ║ diabetes ║ estrogen HRT ║
╠═══════════╬════════════╬═════╬════════╬══════════════╬══════════╬══════════════╣
║ 934988    ║          1 ║  65 ║ M      ║            1 ║        1 ║            0 ║
║ 94044     ║          0 ║  69 ║ F      ║            1 ║        0 ║            0 ║
║ 689348    ║          0 ║  56 ║ F      ║            0 ║        1 ║            1 ║
║ 902498    ║          1 ║  45 ║ M      ║            0 ║        0 ║            1 ║
║ …         ║            ║     ║        ║              ║          ║              ║
╚═══════════╩════════════╩═════╩════════╩══════════════╩══════════╩══════════════╝

我想创建一个输出 table 来传达以下信息:

╔══════════════╦════════╦══════════╦══════════╦══════════╦═══════════╗
║              ║ total  ║M lt50 yo ║F lt50 yo ║M gte50yo ║F gte 50yo ║
╠══════════════╬════════╬══════════╬══════════╬══════════╬═══════════╣
║ estrogen HRT ║    347 ║        2 ║       65 ║        4 ║        97 ║
║ diabetes     ║  13922 ║       54 ║       73 ║      192 ║       247 ║
║ hypertension ║   8210 ║      102 ║      187 ║      443 ║       574 ║
╚══════════════╩════════╩══════════╩══════════╩══════════╩═══════════╝

Total 是患有该合并症的患者总数(很简单:sum(data$estrogen == 1) 等)。其他单元格现在是该年龄和性别分层中患有该合并症的患者人数,其中 had_stroke==1.

我很想大致了解如何解决此类问题,因为它似乎是一种非常基本的数据转换方法。如果总列让它变得时髦,那么请随意排除它。

尽量简单一点。

我假设您有一个名为 datadata.frame。这是一个玩具数据集。

set.seed(0)
data <- data.frame(estrogen = runif(100) < .10,
               diabetes = runif(100) < .15,
               hypertension = runif(100) < .20,
               groups = cut(runif(100), c(0,.1,.4,.7,1), labels = c("my", "fy", "mo", "fo")))

将新变量添加到组的数据框中。

然后,使用 table() 获取摘要

res <- rbind(
  table(data$estrogen, data$groups)[2,],
  table(data$diabetes, data$groups)[2,],
  table(data$hypertension, data$groups)[2,]
)
res <- cbind(apply(res, 1, sum), res)

最后,使用 colnames(res) y rownames(res) 为列和行设置适当的名称。

colnames(res)[1] <- "Total"
rownames(res) <- c("estrogen", "diabetes", "hypertension")

结果

             Total my fy mo fo
estrogen        12  2  2  4  4
diabetes        28  1  8 11  8
hypertension    27  1 10 11  5

所以这是一个 data.table 解决方案。

# create MRE - you have this already
n  <- 1000
set.seed(1)     # for reproducible example
df <- data.frame(ID=sample(1:n,n),had_stroke=sample(0:1,n,replace=TRUE),
                age=sample(25:85,n,replace=TRUE), gender=sample(c("M","F"),n,replace=TRUE),
                hypertension=sample(0:1,n,replace=TRUE),
                diabetes=sample(0:1,n,replace=TRUE),
                estrogen=sample(0:1,n,replace=TRUE))

# you start here.
library(data.table)
result <- melt(setDT(df),measure=5:7, variable.name="comorbidity")
result[,list(total=sum(value==1), 
             M.lt.50=sum(value[gender=="M"&age< 50]),
             F.lt.50=sum(value[gender=="F"&age< 50]),
             M.ge.50=sum(value[gender=="M"&age>=50]),
             F.ge.50=sum(value[gender=="F"&age>=50])),
       by=comorbidity]

#     comorbidity total M.lt.50 F.lt.50 M.ge.50 F.ge.50
# 1: hypertension   521     104     126     143     148
# 2:     diabetes   482     109     120     125     128
# 3:     estrogen   492      99     126     119     148

我知道你要求 dlpyr/tidy(现在我已经提供了一个 MRE 数据集,我相信你会得到一个...)。 IMO data.table 是一个更好的选择:语法并不差,而且几乎总是更快,通常是 10-100 倍。