我有一些 data.tables,其中包含多年来多次检查的患者数据,以及一列,其中包含某些事件发生的年份(假设是心脏病发作)。这是一个玩具示例:
dt <- data.table(patient_ID = c("A","B","C","D"),
heart_attack_year = c(2010, 2011, 2016, 2011),
exam_1_year = c(2005, 2001, 2002, 2002),
exam_2_year = c(2010, 2006, 2010, 2007),
exam_3_year = c(2015, 2012, 2011, 2012),
exam_4_year = c(2020, 2017, 2017, 2014))
我想知道每个患者的心脏病发作时间最接近哪种检查。我编写了一个函数,它将目标年份和不同考试年份的列表 (v) 作为参数,并返回最接近考试的标签:
which_exam_is_closest <- function(target_year, exam_labels, v){
return(exam_labels[which.min(abs(target_year - unlist(v)))])
}
对于不同的数据集,可以有不同数量的检查。不同数据集的考试年份的列名称也不同。因此,我希望能够使用每个数据集可能不同的字符串向量来引用列名称。
for循环可以获取列表v并为每个数据集的每一行调用该函数。例如,对于上面的玩具数据集,我可以写:
exams <- 1:4
closest_exam <- character(0)
for (i in 1:nrow(dt)){
closest_exam <- c(closest_exam, which_exam_is_closest(dt$heart_attack_year[i],
exams,
as.list(dt[i,paste0("exam_",exams,"_year"), with = F])))
}
dt$closest <- closest_exam
这得到了想要的结果:
patient_ID heart_attack_year exam_1_year exam_2_year exam_3_year exam_4_year closest
A 2010 2005 2010 2015 2020 2
B 2011 2001 2006 2012 2017 3
C 2016 2002 2010 2011 2017 4
D 2011 2002 2007 2012 2014 3
但是,使用 for 循环看起来真的很丑陋且效率低下。有没有更好的方法将每个患者的相关数据列表传递给函数,使用列名称向量,并返回“最接近”的列?
您可以逐行减去
abs
which.min
。
> dt[, closest := apply(abs(dt[, 3:6] - unlist(dt[, 2])), 1, which.min)]
> dt
patient_ID heart_attack_year exam_1_year exam_2_year exam_3_year exam_4_year closest
1: A 2010 2005 2010 2015 2020 2
2: B 2011 2001 2006 2012 2017 3
3: C 2016 2002 2010 2011 2017 4
4: D 2011 2002 2007 2012 2014 3