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.
我很想大致了解如何解决此类问题,因为它似乎是一种非常基本的数据转换方法。如果总列让它变得时髦,那么请随意排除它。
尽量简单一点。
我假设您有一个名为 data
的 data.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 倍。
我正在尝试使用 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.
我很想大致了解如何解决此类问题,因为它似乎是一种非常基本的数据转换方法。如果总列让它变得时髦,那么请随意排除它。
尽量简单一点。
我假设您有一个名为 data
的 data.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 倍。