我想在data.table
对象中创建一个新列,并且应该根据匹配范围中的数字来设置值。范围的from
和to
是现有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
[我的方法]
在这种情况下,我想添加一个新的boolean
列flag
,如果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)
变大,则会花费更多时间。
我的问题是:有更好的方法吗?在速度和代码可读性方面更好(我相信我的代码根本不直观)。
答案 0 :(得分:2)
抱歉,你为什么不这样做:
DT[,flag:=0]
DT[from<=6500 & to>=6500,flag:=1]
除非我不明白你的问题,否则应该有相同的结果。
答案 1 :(得分:2)
为什么不使用:
DT[, flag := +(from < 6500 & to > 6500)]
()
之间的陈述给出了条件,+
使其成为逻辑整数(0
或1
)。这给出了与结果相同的结果:
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