Uwe 和 GKi 的答案都是正确的。 Gki 收到了赏金,因为 Uwe 迟到了,但 Uwe 的解决方案运行速度大约是原来的 15 倍
我有两个数据集,其中包含不同患者在多个测量时刻的分数,如下所示:
df1 <- data.frame("ID" = c("patient1","patient1","patient1","patient1","patient2","patient3"),
"Days" = c(0,25,235,353,100,538),
"Score" = c(NA,2,3,4,5,6),
stringsAsFactors = FALSE)
df2 <- data.frame("ID" = c("patient1","patient1","patient1","patient1","patient2","patient2","patient3"),
"Days" = c(0,25,248,353,100,150,503),
"Score" = c(1,10,3,4,5,7,6),
stringsAsFactors = FALSE)
> df1
ID Days Score
1 patient1 0 NA
2 patient1 25 2
3 patient1 235 3
4 patient1 353 4
5 patient2 100 5
6 patient3 538 6
> df2
ID Days Score
1 patient1 0 1
2 patient1 25 10
3 patient1 248 3
4 patient1 353 4
5 patient2 100 5
6 patient2 150 7
7 patient3 503 6
Column ID
显示患者 ID、列Days
显示测量时刻(自患者纳入后的天数)和列Score
显示测量的分数。两个数据集显示相同的数据,但时间不同(df1 是 2 年前的数据,df2 具有相同的数据,但从今年开始更新)。
我必须比较每个患者和两个数据集之间每个时刻的分数。然而,在某些情况下Days
变量随着时间的推移会有微小的变化,因此通过简单的连接来比较数据集是行不通的。例子:
library(dplyr)
> full_join(df1, df2, by=c("ID","Days")) %>%
+ arrange(.[[1]], as.numeric(.[[2]]))
ID Days Score.x Score.y
1 patient1 0 NA 1
2 patient1 25 2 10
3 patient1 235 3 NA
4 patient1 248 NA 3
5 patient1 353 4 4
6 patient2 100 5 5
7 patient2 150 NA 7
8 patient3 503 NA 6
9 patient3 538 6 NA
此处,第 3 行和第 4 行包含相同测量的数据(得分为 3),但未连接,因为Days
列不同(235 与 248)。
问题:我正在寻找一种在第二列上设置阈值(例如 30 天)的方法,这将产生以下输出:
> threshold <- 30
> *** insert join code ***
ID Days Score.x Score.y
1 patient1 0 NA 1
2 patient1 25 2 10
3 patient1 248 3 3
4 patient1 353 4 4
5 patient2 100 5 5
6 patient2 150 NA 7
7 patient3 503 NA 6
8 patient3 538 6 NA
此输出显示先前输出的第 3 行和第 4 行已合并(因为 248-235 Days第二个 df (248) 的。
要记住的三个主要条件是:
- 阈值内的连续天数在同一个 df 中(第 1 行和第 2 行)不合并.
- 在某些情况下,最多可以有四个值
Days
变量存在于同一数据框中,因此不应合并。可能的情况是,这些值之一确实存在于另一个数据帧的阈值内,并且必须将这些值合并。请参阅下面示例中的第 3 行。
- 每个分数/天数/患者组合只能使用一次。如果合并满足所有条件但仍然可能存在双重合并,则应使用第一个合并。
> df1
ID Days Score
1 patient1 0 1
2 patient1 5 2
3 patient1 10 3
4 patient1 15 4
5 patient1 50 5
> df2
ID Days Score
1 patient1 0 1
2 patient1 5 2
3 patient1 12 3
4 patient1 15 4
5 patient1 50 5
> df_combined
ID Days Score.x Score.y
1 patient1 0 1 1
2 patient1 5 2 2
3 patient1 12 3 3
4 patient1 15 4 4
5 patient1 50 5 5
编辑 Chinsoon12
> df1
ID Days Score
1: patient1 0 1
2: patient1 116 2
3: patient1 225 3
4: patient1 309 4
5: patient1 351 5
6: patient2 0 6
7: patient2 49 7
> df2
ID Days Score
1: patient1 0 11
2: patient1 86 12
3: patient1 195 13
4: patient1 279 14
5: patient1 315 15
6: patient2 0 16
7: patient2 91 17
8: patient2 117 18
我将您的解决方案包装在如下函数中:
testSO2 <- function(DT1,DT2) {
setDT(DT1);setDT(DT2)
names(DT1) <- c("ID","Days","X")
names(DT2) <- c("ID","Days","Y")
DT1$Days <- as.numeric(DT1$Days)
DT2$Days <- as.numeric(DT2$Days)
DT1[, c("s1", "e1", "s2", "e2") := .(Days - 30L, Days + 30L, Days, Days)]
DT2[, c("s1", "e1", "s2", "e2") := .(Days, Days, Days - 30L, Days + 30L)]
byk <- c("ID", "s1", "e1")
setkeyv(DT1, byk)
setkeyv(DT2, byk)
o1 <- foverlaps(DT1, DT2)
byk <- c("ID", "s2", "e2")
setkeyv(DT1, byk)
setkeyv(DT2, byk)
o2 <- foverlaps(DT2, DT1)
olaps <- funion(o1, setcolorder(o2, names(o1)))[
is.na(Days), Days := i.Days]
outcome <- olaps[, {
if (all(!is.na(Days)) && any(Days == i.Days)) {
s <- .SD[Days == i.Days, .(Days = Days[1L],
X = X[1L],
Y = Y[1L])]
} else {
s <- .SD[, .(Days = max(Days, i.Days), X, Y)]
}
unique(s)
},
keyby = .(ID, md = pmax(Days, i.Days))][, md := NULL][]
return(outcome)
}
结果是:
> testSO2(df1,df2)
ID Days X Y
1: patient1 0 1 11
2: patient1 116 2 12
3: patient1 225 3 13
4: patient1 309 4 14
5: patient1 315 4 15
6: patient1 351 5 NA
7: patient2 0 6 16
8: patient2 49 7 NA
9: patient2 91 NA 17
10: patient2 117 NA 18
正如您所看到的,第 4 行和第 5 行是错误的。的价值Score
在 df1 中使用了两次 (4)。这些行周围的正确输出应如下所示,因为每个分数(在本例中为 X 或 Y)只能使用一次:
ID Days X Y
4: patient1 309 4 14
5: patient1 315 NA 15
6: patient1 351 5 NA
下面的数据框代码。
df1 <- data.frame(
ID = rep(c("patient1", "patient2"), c(5L, 2L)),
Days = c("0", "116", "225", "309", "351", "0", "49"),
Score = 1:7
)
df2 <- data.frame(
ID = rep(c("patient1", "patient2"), c(5L, 3L)),
Days = c("0", "86", "195", "279", "315", "0", "91", "117"),
Score = 11:18
)