r - R按data.table中的条件分组

标签 r grouping data.table

在R中,我有一个很大的data.table。对于每一行,我想对具有相似x1值(+/-某些公差,tol)的行进行计数。我可以使用adply使其正常工作,但是它太慢了。似乎data.table会很适合-实际上,我已经在使用data.table进行部分计算了。

有没有办法完全使用data.table做到这一点?这是一个例子:

library(data.table)
library(plyr)
my.df = data.table(x1 = 1:1000,
                   x2 = 4:1003)
tol = 3
adply(my.df, 1, function(df) my.df[x1 > (df$x1 - tol) & x1 < (df$x1 + tol), .N])

结果:
        x1   x2 V1
   1:    1    4  3
   2:    2    5  4
   3:    3    6  5
   4:    4    7  5
   5:    5    8  5
  ---             
 996:  996  999  5
 997:  997 1000  5
 998:  998 1001  5
 999:  999 1002  4
1000: 1000 1003  3

更新:

这是一个样本数据集,它与我的真实数据更加接近:
set.seed(10)
x = seq(1,100000000,100000)
x = x + sample(1:50000, length(x), replace=T)
x2 = x + sample(1:50000, length(x), replace=T)
my.df = data.table(x1 = x,
                   x2 = x2)
setkey(my.df,x1)
tol = 100000

og = function(my.df) {
  adply(my.df, 1, function(df) my.df[x1 > (df$x1 - tol) & x1 < (df$x1 + tol), .N])
}

microbenchmark(r_ed <- ed(copy(my.df)),
               r_ar <- ar(copy(my.df)),
               r_og <- og(copy(my.df)),
               times = 1)

Unit: milliseconds
                    expr         min          lq      median          uq         max neval
 r_ed <- ed(copy(my.df))    8.553137    8.553137    8.553137    8.553137    8.553137     1
 r_ar <- ar(copy(my.df))   10.229438   10.229438   10.229438   10.229438   10.229438     1
 r_og <- og(copy(my.df)) 1424.472844 1424.472844 1424.472844 1424.472844 1424.472844     1

显然,@ eddi和@Arun的解决方案都比我的要快得多。现在,我只需要试着理解面包卷。

最佳答案

这里有一个更快的data.table解决方案。这个想法是使用data.table的滚动合并功能,但在此之前,我们需要稍微修改数据并使列x1成为数字而不是整数。这是因为OP使用严格的不等式,并且要使用滚动连接,因此我们将不得不将容忍度降低一点,使其成为浮点数。

my.df[, x1 := as.numeric(x1)]

# set the key to x1 for the merges and to sort
# (note, if data already sorted can make this step instantaneous using setattr)
setkey(my.df, x1)

# and now we're going to do two rolling merges, one with the upper bound
# and one with lower, then get the index of the match and subtract the ends
# (+1, to get the count)
my.df[, res := my.df[J(x1 + tol - 1e-6), list(ind = .I), roll = Inf]$ind -
               my.df[J(x1 - tol + 1e-6), list(ind = .I), roll = -Inf]$ind + 1]


# and here's the bench vs @Arun's solution
ed = function(my.df) {
  my.df[, x1 := as.numeric(x1)]
  setkey(my.df, x1)
  my.df[, res := my.df[J(x1 + tol - 1e-6), list(ind = .I), roll = Inf]$ind -
                 my.df[J(x1 - tol + 1e-6), list(ind = .I), roll = -Inf]$ind + 1]
}

microbenchmark(ed(copy(my.df)), ar(copy(my.df)))
#Unit: milliseconds
#            expr       min       lq   median       uq      max neval
# ed(copy(my.df))  7.297928 10.09947 10.87561 11.80083 23.05907   100
# ar(copy(my.df)) 10.825521 15.38151 16.36115 18.15350 21.98761   100

注意:Arun和Matthew都指出,如果x1是整数,则不必将其转换为数字并从tol中减去一小部分,并且可以使用tol - 1L代替上面的tol - 1e-6

关于r - R按data.table中的条件分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18119663/

相关文章:

r - 将单行数据拆分为多行

r - Union n igraphs后如何恢复属性?

r - 了解 `Reduce`函数

javascript - 如何按对象的子对象对对象列表进行最佳分组?

r - 基本-T检验->分组因子必须具有准确的2个级别

r - 使用分位数箱的 ID 的 data.table 中的新列值

r - 来自 DF 列的 Shiny selectInput

arrays - 如何在二维数组中查找和存储值组?

r - 加快插值练习

r - 每组相同值的最长连续计数