【问题标题】:Improving lookup performance with large data table使用大型数据表提高查找性能
【发布时间】: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


【解决方案1】:

我会这样做:

setDT(z)

dt1[, range := ip_to - ip_from] #calculate all ranges

setorder(dt1, range) #order by ranges

#do a data.table non-equi join taking only the first match
dt1[z, .(Obs = Obs, vl = x.vl, ip_from = x.ip_from, ip_to = x.ip_to),
    on = c("ip_from <= Obs", "ip_to >= Obs"), mult = "first"]
#   Obs vl ip_from ip_to
#1:   8  E       7     9
#2:   6  D       6     6

比较:

print(zzz)
#  Obs ip_from ip_to vl
#1   8       7     9  E
#2   6       6     6  D

【讨论】:

  • 这样快多了。谢谢!!
猜你喜欢
  • 2012-07-13
  • 2014-05-11
  • 1970-01-01
  • 1970-01-01
  • 2012-04-19
  • 2020-08-05
  • 1970-01-01
  • 2013-07-06
  • 1970-01-01
相关资源
最近更新 更多