2015-04-15 57 views
0

我想(内部)基于我有的相似性函数连接两个数据帧。 例如:基于用户定义的函数连接两个数据帧

data1<-data.frame(a=c(1,2,3),lat=c(38.862976,37.878146,36.825658), lon=c(-99.336782,-99.326054,-98.475976)) 
data2<-data.frame(b=c(10,20),lat=c(38.863412,37.877333), lon=c(-99.336701,-99.325151)) 

,并给予了相似的功能:

are.close(lat1,long1,lat2,long2) 

data3<-join(a=data1,b=data2,by=c(lat,lon),FUN=are.close(a.lat,a.lon,b.lat,b.lon)) 

我希望收到的输出是:

a b lat  lon 
1 1 10 38.862976 -99.336782 
2 2 20 37.878146 -99.326054 

凡LAT/lon属于其中一个表(不管哪个,都说第一个)。

我检查的所有连接/合并方法都不允许您定义连接的发生方式。它只允许你指定像col1 = col2这样的东西。

有没有办法做到这一点在计算上是有效的(不是通过在两组上运行两个循环)?

回答

1

我不知道这样做的功能(但当然可能是...),所以我会尝试自己编写一些代码。取决于数据,这可能很困难。但假设情侣真的很清楚(例如,点1的纬度可能最接近b 10,而经度可能更接近b 20等),这可能是开始使用的东西:

data1<-data.frame(a=c(1,2,3),lat=c(38.862976,37.878146,36.825658), lon=c(-99.336782,-99.326054,-98.475976)) 
data2<-data.frame(b=c(10,20),lat=c(38.863412,37.877333), lon=c(-99.336701,-99.325151)) 

# calculate which is the closest value 
names(data1)=c("a","lat_original","lon_original") 
closest=function(x,to=to) to[which.min(abs(to - x))] 
data1$lat=sapply(data1$lat_original,function(x) closest(x,to=data2$lat)) 
data1$lon=sapply(data1$lon_original,function(x) closest(x,to=data2$lon)) 

# if dataframes are not equally big: remove biggest assigned "closest values" (or doubles?) 
if(nrow(data1)!=nrow(data2)) { 
    data1$diff=abs(data1$lat-data1$lat_original)+abs(data1$lon-data1$lon_original) 
    maxN <- function(x, N=N){ 
    x=x[!is.na(x)] 
    len=length(x) 
    if(N>len){ 
    warning('N greater than length(x). Setting N=length(x)') 
    N=length(x) 
    } 
    sort(x,partial=len-N+1)[as.numeric(len-N+1):len] 
} 
data1=data1[!data1$diff %in% maxN(data1$diff,N=nrow(data1)-nrow(data2)),]} 

# perhaps check if doubles (two different points of data 1 assigned to the same point in data2) 
which(duplicated(paste(data1$lat,data1$lon))==T) 

#merge based on those closest values 
merge(data1,data2,by=c("lat","lon")) 
2

这是一个使用dplyr的方法。我假定are.close()被矢量化,并返回TRUE/FALSE,例如这将与函数的工作就像are.close <- function(a, b, c, d) (a-c)^2 + (b-d)^2 < 1

library(dplyr) 
expand.grid(a = data1$a, b = data2$b) %>% 
    left_join(data1, by = "a") %>% 
    left_join(data2, by = "b") %>% 
    mutate(close = are.close(lat.x, lon.x, lat.y, lon.y)) %>% 
    filter(close) 
3

我使用outer识别(A,B)对符合标准建议:

neighbormat <- outer(
    1:nrow(data1), 
    1:nrow(data2), 
    function(i1,i2){ 
    are.close(
     data1$lat[i1], 
     data1$lon[i1], 
     data2$lat[i2], 
     data2$lon[i2] 
    ) 
    } 
) 
dimnames(neighbormat) <- list(data1$a,data2$b) 

使用名称只有在ab是唯一的时才有意义,但我认为它们是自从OP以这种方式使用它们。对于@ konvas的are.close功能,这给

 10 20 
1 TRUE TRUE 
2 TRUE TRUE 
3 FALSE FALSE 

为了得到(A,B),满足标准对使用

ns <- which(neighbormat,arr.ind=TRUE,use.names=TRUE) 
dimnames(ns) <- list(NULL,c("a","b")) 

    a b 
[1,] 1 1 
[2,] 2 1 
[3,] 1 2 
[4,] 2 2 

这是简单的将这些合并回原始数据。 (尽管OP采取了任意(lat,lon),但似乎是一个非常糟糕的主意。)