首页 > 解决方案 > 如何使这个嵌套的 for 循环更快?

问题描述

for (i in 1:nrow(surgeries_7)){ 
  count = 0 
  for (j in 1:nrow(visits_1)){ 
    count <- ifelse(surgeries_7$PatientProfileId[i]==visits_1$PatientProfileId[j] 
                      & visits_1$visit_date[j] > surgeries_7$surgery_date[i] &  
           visits_1$visit_date[j] <= surgeries_7$one_year_from_surgery[i],1,0) 
    surgeries_7$post_op_visits[i] <- surgeries_7$post_op_visits[i] + count 
  } 
  print(i) 
} 

有两个表:surgical_7 是一个:它有两列,PatientProfileId(unique),我们有每个相应配置文件 ID 的手术日期。

第二个表是访问表,其中我们有不同访问的配置文件 ID(相同配置文件 ID 的多个条目)。

我们正在尝试计算手术日期之后(存在于 Surgery_7 表中)但在手术日期后一年内访问表中的访问次数(每个配置文件 id 的条目)。

问题是代码需要很长时间才能运行大约 6k 行。有没有办法让循环更快?

标签: rperformanceloopsfor-loopnested

解决方案


使用 non-equi join indata.table包的选项:

#calculate date one year after surgery
surgery_7[, oneyr := as.IDate(sapply(surgery_date, function(x) 
    seq(x, by="1 year", length.out=2L)[2L]))]

            #update by reference
surgery_7[, post_op_visits := 
    #non-equi join
    visits_1[.SD, on=.(PatientProfileId, visit_date>=surgery_date, visit_date<=oneyr),
        #for each row of surgery_7 find the number of rows from visits_1
        by=.EACHI, .N]$N]

输出surgery_7

   PatientProfileId surgery_date      oneyr post_op_visits
1:                1   2018-01-01 2019-01-01              2
2:                2   2019-01-01 2020-01-01              1

数据:

library(data.table)
surgery_7 <- data.table(PatientProfileId=c(1,2), 
    surgery_date=as.IDate(c("2018-01-01", "2019-01-01")))
#   PatientProfileId surgery_date
#1:                1   2018-01-01
#2:                2   2019-01-01

visits_1 <- data.table(PatientProfileId=c(1,1,1,2,2),
    visit_date=as.IDate(c("2018-03-15","2018-09-15","2019-02-03","2019-06-30","2020-01-15")))
#    PatientProfileId visit_date
# 1:                1 2018-03-15
# 2:                1 2018-09-15
# 3:                1 2019-02-03
# 4:                2 2019-06-30
# 5:                2 2020-01-15

推荐阅读