我有一个大型数据集和一个查找表.我需要为数据集中的每一行返回查找中满足条件的行的最小值.
鉴于我的数据集的大小,我不愿意通过交叉连接来共同破解一个iffy解决方案,因为这将创建数百万条记录.我希望有人可以建议一个(理想情况下)利用base r或data.table的解决方案,因为它们已经以高效的方式使用.
例
A<-seq(1e4,9e4,1e4)
B<-seq(0,1e4,1e3)
dt1<-data.table(expand.grid(A,B),ID=1:nrow(expand.grid(A,B)))
setnames(dt1, c("Var1","Var2"),c("A","B"))
lookup<-data.table(minA=c(1e4,1e4,2e4,2e4,5e4),
maxA=c(2e4,3e4,7e4,6e4,9e4),
minB=rep(2e3,5),
Val=seq(.1,.5,.1))
# Sample Desired Value
A B ID Val
99: 90000 10000 99 0.5
在SQL中,我会写一些东西
SELECT ID, A, B, min(Val) as Val
FROM dt1
LEFT JOIN lookup on dt1.A>=lookup.minA
and dt1.A<=lookup.maxA
and dt1.B>=lookup.minB
GROUP BY ID, A, B
这将从查找到dt1连接所有匹配的记录并返回最小的Val.
更新
到目前为止我的解决方案如下:
CJ.table<-function(X,Y) setkey(X[,c(k=1,.SD)],k)[Y[,c(k=1,.SD)],allow.cartesian=TRUE][,k:=NULL]
dt1.lookup<- CJ.table(dt1,lookup)[A>=minA & A<=maxA & B>=minB,
list(Val=Val[which.min( Val)]),
by=list(ID,A,B)]
dt1.lookup<-rbind.fill(dt1.lookup, dt1[!ID %in% dt1.lookup$ID])
这将检索所有记录,并允许在需要时从查找表中返回其他列.它还具有强制选择最小Val的优点.
最佳答案 我发现没有交叉连接的解决方案首先需要通过去除A和B完全超出范围的行来准备数据:
Prep = dt1[A >= min(lookup$minA) & A <= max(lookup$maxA) & B >= min(lookup$minB)]
然后,您创建一个数据表,其中满足与最低Val对应的每个条件:
Indices = Prep[,list(min(which(A >= lookup$minA)),
min(which(A <= lookup$maxA)),
min(which(B >= lookup$minB)), A, B),by=ID]
那么你必须在满足所有三个条件的最低点得到Val:
Indices[,list(Val=lookup$Val[max(V1,V2,V3)], A, B),by=ID]
看看这是否能满足您的需求:
ID Val A B
1: 19 0.1 10000 2000
2: 20 0.1 20000 2000
3: 21 0.2 30000 2000
4: 22 0.3 40000 2000
5: 23 0.3 50000 2000
6: 24 0.3 60000 2000
7: 25 0.3 70000 2000
8: 26 0.5 80000 2000
9: 27 0.5 90000 2000
10: 28 0.1 10000 3000