我有重复的患者ID,对于一个变量(年龄),其行是相同的。但是,还有一个年龄检查变量,它说明哪一行可能是正确的。年龄最接近“年龄检查”的行是我要保留的行。因此,对于id = 3,值31比28更接近30。因此,我想删除包含age_check == 28的行。我想在R中使用data.table。
id <- c(1,2,3,3,4,5)
age <- c(20,20,30,30,35,40)
age_check <- c(20,20,31,28,35,40)
dat <- data.table(id,age,age_check) #Create the data.table I used
id age age_check
1: 1 20 20
2: 2 20 20
3: 3 30 31
4: 3 30 28
5: 4 35 35
6: 5 40 40
#ID 3 contains a duplicate for which I'd like to keep row 3
输出应为:
id age age_check
1: 1 20 20
2: 2 20 20
3: 3 30 31
5: 4 35 35
6: 5 40 40
我已经尝试/开始使用roll =功能和以下代码:
res <- unique(dat[, .(id)])
res[, w := dat[c(.SD, age = age_check), on =.(id, age), roll= "nearest", which=TRUE]]
该想法已经在较早的文章中提供,但不适用于一行中的值。 谢谢!
答案 0 :(得分:1)
应该不言自明:
dat[, .SD[which.min(abs(age - age_check))], by = .(id, age)]
# id age age_check
#1: 1 20 20
#2: 2 20 20
#3: 3 30 31
#4: 4 35 35
#5: 5 40 40
答案 1 :(得分:0)
您不必合并。您可以只从age
中减去age_check
,然后使该行保持最小值。 tidyverse
解决方案是
library(tidyverse)
dat %>%
mutate(new = abs(age - age_check)) %>%
group_by(id) %>%
slice(which.min(new)) %>%
select(-new)
给出,
# A tibble: 5 x 3 # Groups: id [5] id age age_check <dbl> <dbl> <dbl> 1 1 20 20 2 2 20 20 3 3 30 31 4 4 35 35 5 5 40 40
答案 2 :(得分:0)
您可以执行以下操作(假设对于所有非重复行,age_check等于年龄):
dat[, min_dist := abs(age-age_check) == min(abs(age-age_check)), by = id]
dat <- dat[min_dist == T][, min_dist := NULL]
> dat
id age age_check
1: 1 20 20
2: 2 20 20
3: 3 30 31
4: 4 35 35
5: 5 40 40
如果未重复行的年龄检查并不总是等于年龄,则可以执行以下操作:
dat[, dup_id := duplicated(id) | duplicated(id, fromLast = T)] #find duplicates
dat[, min_dist := abs(age-age_check) == min(abs(age-age_check)), by = id]
dat <- dat[dup_id == F | min_dist == T][, c("dup_id", "min_dist") := NULL]
答案 3 :(得分:0)
使用tidyverse
,如果没有重复的最近值(因为filter()
返回具有给定值的所有行),则可以使用:
dat %>%
group_by(id) %>%
filter(abs(age-age_check) == min(abs(age-age_check)))
id age age_check
<dbl> <dbl> <dbl>
1 1. 20. 20.
2 2. 20. 20.
3 3. 30. 31.
4 4. 35. 35.
5 5. 40. 40.
如果还存在重复的最接近值,则可以尝试:
dat %>%
mutate(temp = abs(age-age_check)) %>%
group_by(id) %>%
top_n(-1) %>%
select(-temp)
或者,如果您更喜欢基数R:
do.call(rbind, by(dat, dat$id, function(x) x[which.min(abs(x$age-x$age_check)), ]))
id age age_check
1: 1 20 20
2: 2 20 20
3: 3 30 31
4: 4 35 35
5: 5 40 40