首页 > 解决方案 > 在 R 中使用 apply() 进行嵌套 for 循环

问题描述

我在 R 中编写了一个嵌套的 for 循环,但循环运行时间太长。我有两个大数据集。对于 dfA 中的每一行和 dfB 中的每一行,循环应该查看 dfA 中的日期是否在 dfB 中的日期间隔内。如果这是真的,那么两个数据集应该在该行的给定列上合并。我不确定我编写的代码是否可以正常工作,因为循环仍在运行。

任何见解将不胜感激。

东风:


       Common    a       Date 
1 20141331123    1        2005-01-01 
2 20141331123    2        2005-01-02 
3 20141331123    3        2005-01-03 
4 20141331123    4        2005-01-04 
5 20141331123    5        2005-01-05 
6 20141331123    6        2005-01-06 

dfB:


  cDate       bDate      common                      
1 2005-01-01 2005-06-13  20141331123 

dfB$Interval <- interval(ymd(dfB$cDate), ymd(dfB$bDate)) 

library(lubridate) 

for (i in 1:nrow(dfA)) {
  
  for (i in 1:nrow(dfB)) {
  
      if (dfA$Date[i] %within% dfB$Interval[i] == TRUE) {
        
        merged <- merge(dfA, dfB, by.x = c("common"), by.y = c("Common"))
        
      }
    
  }
  
  return(merged)

}

标签: rapplynested-loops

解决方案


SQL 原生支持不等连接, R 也支持不等连接data.table。基本 R 和tidyverse函数都不支持本地 [1]。

library(data.table)
setDT(dfA)
setDT(dfB)
dfB[dfA, on = .(common == Common, cDate <= Date, bDate >= Date)]
#         cDate      bDate      common a
# 1: 2005-01-01 2005-01-01 20141331123 1
# 2: 2005-01-02 2005-01-02 20141331123 2
# 3: 2005-01-03 2005-01-03 20141331123 3
# 4: 2005-01-04 2005-01-04 20141331123 4
# 5: 2005-01-05 2005-01-05 20141331123 5
# 6: 2005-01-06 2005-01-06 20141331123 6

样本数据有点无趣,因为所有内容都适合单个区间,但也许这将适用于您的更多样化的数据。

[1]:由于 SQL 支持,所以在dbplyr使用sql_on.


数据:

dfA <- structure(list(Common = c("20141331123", "20141331123", "20141331123", "20141331123", "20141331123", "20141331123"), a = 1:6, Date = structure(c(12784, 12785, 12786, 12787, 12788, 12789), class = "Date")), row.names = c(NA, -6L), class = "data.frame")
dfB <- structure(list(cDate = structure(12784, class = "Date"), bDate = structure(12947, class = "Date"), common = "20141331123"), row.names = c(NA, -1L), class = "data.frame")

推荐阅读