我有一个大型数据集和一个查找表。我需要为数据集中的每一行返回查找中满足条件的行的最小值。
考虑到我的数据集的大小,我不愿意通过交叉连接一起破解一个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
哪个会将所有匹配的记录从lookup
加到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的好处。
答案 0 :(得分:1)
我发现没有交叉加入的解决方案首先需要通过删除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
答案 1 :(得分:1)
我的第一个想法是试图制作一个像Senor O这样的指数。然而,min(Val)使得索引表更加难以让我思考。我想这样做的方法是遍历查找表。
dt1[,Val:=as.numeric(NA)]
for (row in 1:NROW(lookup)) {
dt1[A>=lookup[order(Val)][row,minA]&A<=lookup[order(Val)][row,maxA]&B>=lookup[order(Val)][row,minB]&is.na(Val),Val:=lookup[order(Val)][row,Val]]
}
我认为这应该有效,因为它首先使用NA
值设置新列。
然后它按Val
顺序放置查找表,这样你就可以得到它的最低值。
在每个循环中,如果 dt1
中的值仍为NA
中的Val
且我们正在循环{{1}按照最小lookup
到最大的顺序,它将确保您获得所需的Val
。
用
替换rbind.fill行min(Val)
它将消除对rbindlist(list(dt1.lookup,dt1[!ID %in% dt1.lookup[,ID]][,list(ID, A, B, Val=as.numeric(NA))]))
包的依赖,我认为它会更快。