我正在尝试(内部)基于我拥有的相似性函数连接两个数据帧。 例如:
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。
这样的东西有没有办法计算效率(不是通过在两组上运行两个循环)?
答案 0 :(得分: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)
如果a
和b
是唯一的,那么使用这些名称才有意义,但我会假设它们是因为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
将这些合并回原始数据非常简单。 (尽管如此,采取任意(纬度,经度)可能是一个非常糟糕的主意。)
答案 1 :(得分: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)
答案 2 :(得分: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"))