从其他数据框中查找最近的点

时间:2016-10-24 06:29:06

标签: r dataframe distance closest

我有两个数据框,一个是带有x和Y坐标的80万行,另一个数据框是带有X和Y坐标的70000行。我想知道R中的逻辑和代码,我想将第1帧的数据点与数据帧2中的最近点相关联。是否有任何标准包可以这样做?

我正在运行嵌套for循环。但这非常缓慢,因为它的迭代次数为80万* 70000次,非常耗时。

请帮忙 -

1 个答案:

答案 0 :(得分:2)

我找到了一种使用data.table库获得预期结果的更快方法:

library(data.table)

time0 <- Sys.time()

以下是一些随机数据:

df1 <- data.table(x = runif(8e5), y = runif(8e5))
df2 <- data.table(x = runif(7e4), y = runif(7e4))

假设(x,y)是标准坐标系中的坐标,您可以计算距离的平方如下:

dist <- function(a, b){
                dt <- data.table((df2$x-a)^2+(df2$y-b)^2)
                return(which.min(dt$V1))}

现在您可以将此功能应用于您的数据以获得预期结果:

results <- df1[, j = list(Closest =  dist(x, y)), by = 1:nrow(df1)]

time1 <- Sys.time()
print(time1 - time0)

我花了大约30分钟才把结果放在慢速计算机上。

修改

根据要求,我使用sapply或使用adply包中的plyr尝试了其他几种解决方案。我已经在较小的数据帧上测试了这些解决方案,以使其更快。

library(data.table)
library(plyr)
library(microbenchmark)

########################
## Test 1: data.table ##
########################

dt1 <- data.table(x = runif(1e4), y = runif(1e4))
dt2 <- data.table(x = runif(5e3), y = runif(5e3))

dist1 <- function(a, b){
                dt <- data.table((dt2$x-a)^2+(dt2$y-b)^2)
                return(which.min(dt$V1))}

results1 <- function() return(dt1[, j = list(Closest =  dist1(x, y)), by = 1:nrow(dt1)])

###################
## Test 2: adply ##
###################

df1 <- data.frame(x = runif(1e4), y = runif(1e4))
df2 <- data.frame(x = runif(5e3), y = runif(5e3))

dist2 <- function(df){
                dt <- data.table((df2$x-df$x)^2+(df2$y-df$y)^2)
                return(which.min(dt$V1))}

results2 <- function() return(adply(.data = df1, .margins = 1, .fun = dist2))

####################
## Test 3: sapply ##
####################

df1 <- data.frame(x = runif(1e4), y = runif(1e4))
df2 <- data.frame(x = runif(5e3), y = runif(5e3))

dist2 <- function(df){
                dt <- data.table((df2$x-df$x)^2+(df2$y-df$y)^2)
                return(which.min(dt$V1))}

results3 <- function() return(sapply(1:nrow(df1), function(x) return(dist2(df1[x,]))))

microbenchmark(results1(), results2(), results3(), times = 20)

#Unit: seconds
#       expr      min       lq     mean   median       uq      max neval
# results1() 4.046063 4.117177 4.401397 4.218234 4.538186 5.724824    20
# results2() 5.503518 5.679844 5.992497 5.886135 6.041192 7.283477    20
# results3() 4.718865 4.883286 5.131345 4.949300 5.231807 6.262914    20

第一种解决方案似乎明显快于其他解决方案。对于更大的数据集来说更是如此。