在R中的条件下找到多行的最大值
find maximum value for multiple rows on condition in R
我遇到了以下问题。我需要跟踪每个 ID
在系列中每次测量前后 3 小时内的 crp
和 gluc
的最大值。在过去的几个月里,我尝试了不同的解决方案,但未能解决这个问题。我有一个如下所示的数据集:
ID crp gluc hour
1 5 300 0.3
1 2 NA 0.9
1 NA 89 1.2
1 9 NA 4
1 NA 100 7.1
2 0 NA 0.3
2 NA 50 1
2 NA 70 2.2
2 1 80 5
结果应该是:
ID crp gluc hours maxCrp MaxGluc
1 5 300 0.3 5 300
1 2 NA 0.9 5 300
1 NA 89 1.2 9 300
1 9 NA 4 9 89
1 NA 100 7.1 NA 100
2 0 NA 0.3 0 70
2 NA 50 1 0 70
2 NA 70 2.2 1 80
2 1 80 5 1 80
提前谢谢你,
埃里克
为此使用像 mutate
这样的酷 R 工具很诱人,而且通常很有用,但由于您的问题非常具体,我更喜欢使用 for 循环和清晰的语句来实现您的要求的每个部分。
以下是我的做法:
df1 <- data.frame(ID=c(1,1,1,1,1,2,2,2,2),crp=c(5,2,NA,9,NA,0,NA,NA,1),gluc=c(300,NA,89,NA,100,NA,50,70,80),hour=c(0.3,0.9,1.2,4,7.1,.3,1,2.2,5))
df1$maxCrp <- 0
df1$MaxGluc <- 0
clinical_window <- 3
for (i in 1:nrow(df1)){
mask <- (df1$ID == df1$ID[i]) & (abs(df1$hour-df1$hour[i]) < clinical_window)
df1$maxCrp[i] <- max(df1$crp[mask], na.rm=TRUE)
df1$MaxGluc[i] <- max(df1$gluc[mask], na.rm=TRUE)
}
df1$maxCrp[is.infinite(df1$maxCrp)] <- NA
df1$MaxGluc[is.infinite(df1$MaxGluc)] <- NA
此代码会在缺少数据的地方发出警告。
如果有兴趣,您可以使用 data.table
和以下方法。
这包括非等值自连接,包括 crp
和 gluc
的 max
值,基于介于 +/- 3 之间的 hour
值小时。
tmp
临时 data.table 与 max
结果合并回原始数据。
带有 lapply
的最后一行是 from here 作为从数据 table 中删除无限值的一种方法。
library(data.table)
setDT(dt)
tmp <- dt[dt[, .(ID, hour, lower = hour - 3, upper = hour + 3)]
, on = .(ID = ID, hour >= lower, hour <= upper)
, .(ID, hour, crp, gluc)
, allow.cartesian = TRUE
][, .(maxCrp = max(crp, na.rm = T), maxGluc = max(gluc, na.rm = T))
, by = .(ID, hour)]
dt <- dt[tmp, on = .(ID, hour)]
invisible(lapply(names(dt),
function(.name) set(dt, which(is.infinite(dt[[.name]])),
j = .name, value = NA)))
dt
输出
ID crp gluc hour maxCrp maxGluc
1: 1 5 300 0.3 5 300
2: 1 2 NA 0.9 5 300
3: 1 NA 89 1.2 9 300
4: 1 9 NA 4.0 9 89
5: 1 NA 100 7.1 NA 100
6: 2 0 NA 0.3 0 70
7: 2 NA 50 1.0 0 70
8: 2 NA 70 2.2 1 80
9: 2 1 80 5.0 1 80
我遇到了以下问题。我需要跟踪每个 ID
在系列中每次测量前后 3 小时内的 crp
和 gluc
的最大值。在过去的几个月里,我尝试了不同的解决方案,但未能解决这个问题。我有一个如下所示的数据集:
ID crp gluc hour
1 5 300 0.3
1 2 NA 0.9
1 NA 89 1.2
1 9 NA 4
1 NA 100 7.1
2 0 NA 0.3
2 NA 50 1
2 NA 70 2.2
2 1 80 5
结果应该是:
ID crp gluc hours maxCrp MaxGluc
1 5 300 0.3 5 300
1 2 NA 0.9 5 300
1 NA 89 1.2 9 300
1 9 NA 4 9 89
1 NA 100 7.1 NA 100
2 0 NA 0.3 0 70
2 NA 50 1 0 70
2 NA 70 2.2 1 80
2 1 80 5 1 80
提前谢谢你, 埃里克
为此使用像 mutate
这样的酷 R 工具很诱人,而且通常很有用,但由于您的问题非常具体,我更喜欢使用 for 循环和清晰的语句来实现您的要求的每个部分。
以下是我的做法:
df1 <- data.frame(ID=c(1,1,1,1,1,2,2,2,2),crp=c(5,2,NA,9,NA,0,NA,NA,1),gluc=c(300,NA,89,NA,100,NA,50,70,80),hour=c(0.3,0.9,1.2,4,7.1,.3,1,2.2,5))
df1$maxCrp <- 0
df1$MaxGluc <- 0
clinical_window <- 3
for (i in 1:nrow(df1)){
mask <- (df1$ID == df1$ID[i]) & (abs(df1$hour-df1$hour[i]) < clinical_window)
df1$maxCrp[i] <- max(df1$crp[mask], na.rm=TRUE)
df1$MaxGluc[i] <- max(df1$gluc[mask], na.rm=TRUE)
}
df1$maxCrp[is.infinite(df1$maxCrp)] <- NA
df1$MaxGluc[is.infinite(df1$MaxGluc)] <- NA
此代码会在缺少数据的地方发出警告。
如果有兴趣,您可以使用 data.table
和以下方法。
这包括非等值自连接,包括 crp
和 gluc
的 max
值,基于介于 +/- 3 之间的 hour
值小时。
tmp
临时 data.table 与 max
结果合并回原始数据。
带有 lapply
的最后一行是 from here 作为从数据 table 中删除无限值的一种方法。
library(data.table)
setDT(dt)
tmp <- dt[dt[, .(ID, hour, lower = hour - 3, upper = hour + 3)]
, on = .(ID = ID, hour >= lower, hour <= upper)
, .(ID, hour, crp, gluc)
, allow.cartesian = TRUE
][, .(maxCrp = max(crp, na.rm = T), maxGluc = max(gluc, na.rm = T))
, by = .(ID, hour)]
dt <- dt[tmp, on = .(ID, hour)]
invisible(lapply(names(dt),
function(.name) set(dt, which(is.infinite(dt[[.name]])),
j = .name, value = NA)))
dt
输出
ID crp gluc hour maxCrp maxGluc
1: 1 5 300 0.3 5 300
2: 1 2 NA 0.9 5 300
3: 1 NA 89 1.2 9 300
4: 1 9 NA 4.0 9 89
5: 1 NA 100 7.1 NA 100
6: 2 0 NA 0.3 0 70
7: 2 NA 50 1.0 0 70
8: 2 NA 70 2.2 1 80
9: 2 1 80 5.0 1 80