R数据表与不等条件的连接

11

我想使用data.table包根据多个不等式条件对我的数据进行子集筛选。data.table手册中的示例展示了如何使用字符变量进行此操作,但没有涉及到数值不等式。我也知道可以使用subset函数进行此操作,但我真的想利用data.table的二进制搜索速度。以下是我正在尝试做的示例。

library(data.table)

data <- data.table(X=seq(-5,5,1), Y=seq(-5,5,1), Z=seq(-5,5,1))
data

setkey(data, X, Y, Z)

#the data.frame way
data[X > 0 & Y > 0 & Z > 0]

#the data.table way (does not work as I expected)
data[J(>0, >0, >0)]

4
等等,“使用data.frame方法”在这里能行得通,对吧?事实上,如果使用data.frame方式就会失败。J表示“连接”,它将对象作为第一步进行子集化;但是通过不等式进行子集化才是data.frame的正常方式。 - Frank
9
@Frank +1 我们可能需要对变量i进行一些优化,以便在使用不等式时可以使用键(key)实现。我想人们可以从介绍中得到这个观点,不要使用==,然后期望类似的概念适用于向量扫描>。甚至==也应该使用键(key),因为这更自然。 - Matt Dowle
2
@MatthewDowle 嗯,那将是很酷的事情。像两个点或者 .&(keyvar1的条件, keyvar2的条件,...)这样的东西?我猜目前你需要做的是 tmp <- CJ(keyvars)[conds]; DT[tmp] - Frank
6
更简单的说,DT[X > 0 & Y > 0 & Z > 0] 将自动使用关键字。由于这是R语言,我们可以在评估之前优化 i 表达式。 - Matt Dowle
3
如果我们能够对任何|&的组合使用==><,那就可以开始了。如果这不是优化后的模式,那它就会回退到常规向量扫描。次要键可以自动构建并缓存。 - Matt Dowle
显示剩余3条评论
2个回答

0

我运行了一些基准测试

library(dplyr)
library(data.table)
library(microbenchmark)

dt.data.frame.way <- function(data) data[X > 0 & Y > 0 & Z > 0]
dplyr.way <- function(df) filter(df, X > 0, Y > 0, Z > 0)
real.data.frame.way <- function(df) df[df$X > 0 & df$Y > 0 & df$Z > 0,]

data <- data.table(X=seq(-5,5,1), Y=seq(-5,5,1), Z=seq(-5,5,1))
setkey(data, X, Y, Z)
df <- as.data.frame(data)

microbenchmark(times = 10,
               dt.data.frame.way(data),
               dplyr.way(df),
               real.data.frame.way(df))
# Unit: microseconds
#                     expr     min       lq       mean    median       uq        max neval
#  dt.data.frame.way(data) 710.426  754.287   871.8784  824.7565  942.998   1180.458    10
#            dplyr.way(df) 951.309 1045.246 12303.3462 1142.7440 1246.668 112775.934    10
#  real.data.frame.way(df) 137.239  162.591   181.5254  187.9785  197.373    231.594    10

将示例数据简单克隆到5.5M行。

data <- data.table(X=seq(-5,5,1), Y=seq(-5,5,1), Z=seq(-5,5,1))
data <- rbindlist(lapply(1:5e5, function(i) data)) # 5500000 rows
setkey(data, X, Y, Z)
df <- as.data.frame(data)

microbenchmark(times = 10,
               dt.data.frame.way(data),
               dplyr.way(df),
               real.data.frame.way(df))
# Unit: milliseconds
#                     expr      min        lq      mean    median        uq       max neval
#  dt.data.frame.way(data) 656.2978  668.0560  730.9246  696.6560  831.0877  846.0517    10
#            dplyr.way(df) 632.4096  639.1141  709.4308  678.9436  717.3018 1015.7663    10
#  real.data.frame.way(df) 964.4298 1022.1772 1075.8448 1077.4437 1125.0037 1192.7410    10

看起来那个任务的性能很难提高。通常这取决于数据。


0

它比仅使用 data[X > 0 & Y > 0 & Z > 0] 更快或更简单吗?你进行了基准测试吗?还是你认为编写 filter 比编写 [ 更简单? - David Arenburg
我不是指更快或更简单,而只是dplyr以一种快速和简单的方式解决了这个问题。感谢提醒。 - rafa.pereira

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接