根据从现有列

时间:2015-08-05 19:45:01

标签: r data.table

我想在data.table对象中创建一个新列,并且应该根据匹配范围中的数字来设置值。范围的fromto是现有data.table对象中的两列。

[数据]

library(data.table)
set.seed(1)
DT <- data.table(from=sample(10000))[, to:=from+sample(10000)]

> head(DT)
from    to
1: 2656  3304
2: 3721 10487
3: 5728 13081
4: 9080 10193
5: 2017  2484
6: 8980 10289

[我的方法]

在这种情况下,我想添加一个新的booleanflag,如果6500在TRUE范围内,则返回[from, to]

这是我的尝试:

DT[, flag:=0][DT[, .I[6500 %in% seq(from, to, by=1)], by=1:nrow(DT)][[1]], flag:=1]

> table(DT$flag)

   0    1 
5567 4433 

[问题]

代码需要一些时间才能运行,而且正如您可以想象的那样,如果n中的sample(n)变大,则会花费更多时间。

我的问题是:有更好的方法吗?在速度和代码可读性方面更好(我相信我的代码根本不直观)。

3 个答案:

答案 0 :(得分:2)

抱歉,你为什么不这样做:

DT[,flag:=0]
DT[from<=6500 & to>=6500,flag:=1]

除非我不明白你的问题,否则应该有相同的结果。

答案 1 :(得分:2)

为什么不使用:

DT[, flag := +(from < 6500 & to > 6500)]

()之间的陈述给出了条件,+使其成为逻辑整数(01)。这给出了与结果相同的结果:

DT[, flag := ifelse(from < 6500 & to > 6500, 1, 0)]

另一种可能性(由@Frank建议):

DT[, flag := mapply(between,6500,from,to)]

然而,mapply电话会导致相当多的开销。只需使用:

DT[, flag := between(6500,from,to)]

速度要快得多,可以从以下不同方法之间的速度比较中看出:

library(microbenchmark)
microbenchmark(q = DT[, flag:=0][DT[, .I[6500 %in% seq(from, to, by=1)], by=1:nrow(DT)][[1]], flag:=1],
               j1 = DT[, flag := +(from < 6500 & to > 6500)],
               j2 = DT[, flag := ifelse(from < 6500 & to > 6500, 1, 0)],
               j3 = DT[, flag := mapply(between,6500,from,to)],
               j4 = DT[, flag := between(6500,from,to)],
               nikos = DT[, flag:=0][from<=6500 & to>=6500, flag:=1],
               jimbo = DT[, flag := 6500<=to & 6500>=from])

Unit: microseconds
  expr         min           lq         mean       median           uq         max
     q 2424842.405 2498646.2495 2638230.4775 2545083.2020 2684601.6290 4336768.458
    j1     843.639     896.2505    1074.3921     955.3120    1047.0570    3689.399
    j2    2063.674    2205.7850    2766.0470    2282.0050    3115.9475    7978.479
    j3   16072.188   16406.6920   19550.4140   19056.4665   20915.1620   75465.362
    j4     687.094     731.7385     877.6009     780.1280     858.3825    3073.322
 nikos    1077.945    1186.2395    1424.4156    1290.7015    1389.8500    3699.621
 jimbo     759.372     836.2075    1000.6322     884.4715     958.0035    3016.492

因此,最快的方法(between中的j4选项)比问题中的原始方法快约3000倍。

答案 2 :(得分:0)

library(data.table)
set.seed(1)
DT <- data.table(from=sample(10000))[, to:=from+sample(10000)]
DT[, flag := 6500<=to & 6500>=from]

> table(DT$flag)

FALSE  TRUE 
 5567  4433