r - R基于具有添加条件的特定列合并两个数据集
问题描述
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
列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 < 30)并采用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 行是错误的。df1 中的值Score
被使用了两次 (4)。这些行周围的正确输出应如下所示,因为每个分数(在本例中为 X 或 Y)只能使用一次:
ID Days X Y
4: patient1 309 4 14
5: patient1 315 NA 15
6: patient1 351 5 NA
下面的数据框代码。
> dput(df1)
structure(list(ID = c("patient1", "patient1", "patient1", "patient1",
"patient1", "patient2", "patient2"), Days = c("0", "116", "225",
"309", "351", "0", "49"), Score = 1:7), row.names = c(NA, 7L), class = "data.frame")
> dput(df2)
structure(list(ID = c("patient1", "patient1", "patient1", "patient1",
"patient1", "patient2", "patient2", "patient2"), Days = c("0",
"86", "195", "279", "315", "0", "91", "117"), Score = 11:18), row.names = c(NA,
8L), class = "data.frame")
解决方案
听起来像是对现实但混乱的数据集的数据清理练习,不幸的是,我们大多数人以前都有过这种经验。这是另一种data.table
选择:
DT1[, c("Xrn", "s1", "e1", "s2", "e2") := .(.I, Days - 30L, Days + 30L, Days, Days)]
DT2[, c("Yrn", "s1", "e1", "s2", "e2") := .(.I, 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]
ans <- olaps[, {
if (any(Days == i.Days)) {
.SD[Days == i.Days,
.(Days=Days[1L], Xrn=Xrn[1L], Yrn=Yrn[1L], X=X[1L], Y=Y[1L])]
} else {
.SD[, .(Days=md, Xrn=Xrn[1L], Yrn=Yrn[1L], X=X[1L], Y=Y[1L])]
}
},
keyby = .(ID, md = pmax(Days, i.Days))]
#or also ans[duplicated(Xrn), X := NA_integer_][duplicated(Yrn), Y := NA_integer_]
ans[rowid(Xrn) > 1L, X := NA_integer_]
ans[rowid(Yrn) > 1L, Y := NA_integer_]
ans[, c("md", "Xrn", "Yrn") := NULL][]
以下数据集的输出:
ID Days X Y
1: 1 0 1 11
2: 1 10 2 12
3: 1 25 3 13
4: 1 248 4 14
5: 1 353 5 15
6: 2 100 6 16
7: 2 150 NA 17
8: 3 503 NA 18
9: 3 538 7 NA
OP 编辑中第二个数据集的输出:
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 NA 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
数据(我从其他链接的帖子中添加了更多数据,并简化了数据以便于查看):
library(data.table)
DT1 <- data.table(ID = c(1,1,1,1,1,2,3),
Days = c(0,10,25,235,353,100,538))[, X := .I]
DT2 <- data.table(ID = c(1,1,1,1,1,2,2,3),
Days = c(0,10,25,248,353,100,150,503))[, Y := .I + 10L]
解释:
依次使用每个表作为左表执行 2 次重叠连接。
将右表中设置 NA 天之前的 2 个结果与左表中的结果合并。
按患者和重叠日期分组。如果存在相同的日期,则保留记录。否则使用最大日期。
每个分数只能使用一次,因此删除重复项。
如果您发现这种方法没有给出正确结果的情况,请告诉我。
推荐阅读
- c# - 从服务器接收结果时发生传输级错误错误 C#
- sql - 为什么我在运行此代码时收到“无效标识符”oracle 错误?
- python - Python 词云 - TypeError:预期的字符串
- python - Pycharm 内联文档不适用于 Macbook 中的 python 3.7
- flutter - Flutter - 使用 pushName 获取数据
- php - htaccess 重定向 301 相对路径,在需要 https 时将 url 从 https 重定向到 http
- python - 使用pairplot和相关方法观察数据框不同变量之间的关系
- node.js - 我们如何在提示功能中设置“语言环境”
- javascript - 将 CSV 文件数据加载到 HTML 表中
- github - 纱线:错误:连接 ECONNREFUSED 127.0.0.1:443