我试图使用两个标准来匹配两个数据集(我们称它们为 dfa 和 dfb):距离和时间。两者都有事件发生的时间/地点的准确时间和坐标。我想将 dfb 中 a) 2 公里内和 b) 之前 12 小时内发生的事件数分配给 dfa。数据库 dfa 有 1300 万个观测值,数据库 dfb 有 50 万个观测值。
我使用了两种不同的方法:a)使用矩阵和b)for循环。然而,对于第一种方法,我的内存不足,而对于第二种方法,我需要 6 天以上的时间。有没有更有效的方法来完成这项任务?
示例数据集:
require(chron)
dfa<-data.frame(matrix(ncol = 6, nrow = 13000000))
colnames(dfa)<-c('eventid','date','time','date_time','lat','long')
dfa$eventid<-1:nrow(dfa)
dfa$date<-as.Date(sample(as.Date("2015-01-01"):as.Date("2020-12-31"),2000, replace = T),origin = '1970-01-01')
dfa$time<-sample(0:23,2000,replace=T)
dfa$date_time<-chron(dates=as.numeric(dfa$date),
times=paste0(dfa$time,":00:00"),
format=c(dates="Y-M-D",times="h:m:s"))
dfa$lat<-sample(-4.5:1.5,2000,replace=T)
dfa$long<-sample(-90.5:-75.5,2000,replace=T)
dfb<-data.frame(matrix(ncol = 6, nrow = 500000))
colnames(dfb)<-c('eventid','date','time','date_time','lat','long')
dfb$eventid<-1:nrow(dfb)
dfb$date<-as.Date(sample(as.Date("2015-01-01"):as.Date("2020-12-31"), 2000, replace = T),origin = '1970-01-01')
dfb$time<-sample(0:23,2000,replace=T)
dfb$date_time<-chron(dates=as.numeric(dfb$date),
times=paste0(dfb$time,":00:00"),
format=c(dates="Y-M-D",times="h:m:s"))
dfb$lat<-sample(-4.5:1.5,2000,replace=T)
dfb$long<-sample(-90.5:-75.5,2000,replace=T)
For 循环选项:
require(spatialrisk)
data<-data.frame(matrix(ncol = ncol(dfa), nrow = 1))
colnames(data)<-names(dfa)
data$nbr<-NA
data$timediff<-NA
data$distance<-NA
nro<-0
for(i in 1:nrow(dfa)){
nro<-nro+1
temp<-as.data.frame(dfa[i,])
buff<-points_in_circle(dfb, temp[,6], temp[,5], long, lat, radius= 2000)
buff$timediff<-buff$date_time-temp$date_time
buff<-subset(buff,buff$timediff>=0&buff$timediff<=0.5)
if(nrow(buff)>0){
temp$nbr<-nrow(buff)
temp$timediff<-toString(buff$timediff)
temp$distance<-toString(buff$distance)
} else {
temp$nbr<-0
temp$timediff<-NA
temp$distance<-NA
}
data<-rbind(data,temp)
#Process:
print(paste0(round(nro/nrow(dfa)*100,5),"% done!"))
}
下面描述的方法要快得多,不到一分钟即可完成示例数据集的计算。加速主要是由于数据中只有 2K 个唯一的位置/时间组合。一旦按位置和时间汇总观察结果和事件,所得表格就会小得多。
按位置和时间总结
dfa
和 dfb
后,我们的想法是首先识别在其时间窗口内进行每个观测的 dfa
的子集。然后,仅针对那些观察包含在其时间窗口中的事件(在 points_in_circle
中)对每个观察(在 dfb
中)调用 dfa
。
library(data.table)
system.time({
dfb <- setDT(dfb)[,.(nbr = .N), .(date_time, lat, long)]
dfa <- setDT(dfa)[,.(eventid = .(eventid)), .(date_time, lat, long)]
setkey(dfa, date_time)
setkey(dfb, date_time)
dfa[,`:=`(r = .I, nbr = 0L)]
dfb[,date_time12 := date_time + 0.5][
, c("r1", "r2") := dfa[
dfa[dfb, .(date_time12 = date_time12, r1 = r), roll = -Inf, mult = "first"],
.(r1 = r1, r2 = r), on = .(date_time = date_time12),
roll = Inf, mult = "first"
]
][r1 <= r2][dfa$date_time[r1] >= date_time][,r := .I][
, {
i <- points_in_circle(dfa, long, lat, long, lat, radius = 2e3)$r
dfa$nbr[i] <<- dfa$nbr[i] + nbr
NULL
}, by = r
]
dfa <- dfa[
,lapply(.SD, \(x) if (is.list(x)) unlist(x) else rep(x, lengths(eventid)))
]
setorder(dfa, eventid)
})
#> user system elapsed
#> 28.28 11.38 35.87
结果:
dfa
#> date_time lat long eventid r nbr
#> 1: (15-09-25 08:00:00) 1.5 -80.5 1 248 2000
#> 2: (17-07-28 12:00:00) -0.5 -83.5 2 894 1000
#> 3: (17-10-15 02:00:00) -1.5 -86.5 3 962 1500
#> 4: (20-07-01 20:00:00) -1.5 -83.5 4 1843 1250
#> 5: (18-10-17 04:00:00) -0.5 -78.5 5 1289 1250
#> ---
#> 12999996: (20-03-28 03:00:00) 0.5 -78.5 12999996 1765 2000
#> 12999997: (15-02-13 17:00:00) -2.5 -87.5 12999997 45 2500
#> 12999998: (15-07-18 18:00:00) -1.5 -85.5 12999998 185 1000
#> 12999999: (16-07-19 04:00:00) 1.5 -75.5 12999999 554 1250
#> 13000000: (16-05-29 15:00:00) -3.5 -87.5 13000000 506 2250