【发布时间】:2019-12-26 14:54:47
【问题描述】:
我正在寻找用于提高查找大型(超过一百万行)参考数据表的性能的选项。查找根据表的每一行中的范围匹配一个键。多个匹配是可能的,我可以获取所有匹配的列表或最紧密的匹配(范围最小的匹配)。
下面的代码中显示了一个小玩具示例。
# Create small example dataset with overlapping ranges
#
ip_from <- c(1,2,4,6,7, 7, 8,11)
ip_to <- c(5,3,5,6,9,15,10,15)
vl <- c("A","B","C","D","E","F","G","H")
dt1 <- data.table(ip_from,ip_to,vl,stringsAsFactors=FALSE)
str(dt1)
head(dt1,n=10)
#
# Perform some lookups manually
# A hit is when ip_from<= x <=ip_to
# There can be multiple hits
#
x <- 8
dt2 <- dt1[x>=ip_from & x<=ip_to] #Can produce multiple hits
head(dt2)
y <- dt2[,min(ip_to-ip_from)] #Get smallest difference
dt3 <- dt2[(ip_to-ip_from)==y] #Get hits matching smallest
head(dt3)
dt4 <- dt3[1] #Take first hit if multiples
head(dt4)
#
# Create a function to do the match
# It crudely caters for misses.
#
lkp <- function(dtbl,ky){
dtx <- dtbl[ky>=ip_from & ky<=ip_to]
if (nrow(dtx)!=0) {
y <- dtx[,min(ip_to-ip_from)]
dty <- dtx[(ip_to-ip_from)==y]
dtz <- dty[1]
return(dtz)
}
else {
return(NA)
}
}
#
# Make a set of keys
#
z <- as.data.frame(c(8,6))
colnames(z) <- "Obs"
#
# Do lookups, this gets slow.
#
zz <- rbindlist(apply(z,1,function(x) lkp(dt1,x[1])))
zzz <- cbind(z,zz)
head(zzz)
随着要查找的键数量的增加,性能下降,并且我可能会遇到成千上万个键的情况。请注意,在更实际的情况下,高值和低值是数据表中的键。
还有其他可以显着提高性能的方法吗?
【问题讨论】:
-
永远,永远不要为此使用
apply。它对整个数据进行深度复制,这很慢且占用大量内存。如果您觉得需要像这样对 data.table 行应用函数,则表明您应该将 data.table 重塑为长格式,然后继续执行 by 操作。
标签: r lookup-tables