基于从现有列派生的TRUE/FALSE设置新列值
我想在基于从现有列派生的TRUE/FALSE设置新列值,r,data.table,R,Data.table,我想在data.table对象中创建一个新列,并且应该根据匹配范围内的数字来设置值。范围的from和to是现有数据表中的两列 [数据] 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:
data.table
对象中创建一个新列,并且应该根据匹配范围内的数字来设置值。范围的from
和to
是现有数据表中的两列
[数据]
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
[问题]
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
代码运行需要一些时间,正如您所想象的,如果sample(n)
中的n
变得更大,则需要更多的时间
我的问题是:有更好的方法吗?在速度和代码可读性方面更好(我相信我的代码一点都不直观)。对不起,为什么不这样做:
DT[,flag:=0]
DT[from<=6500 & to>=6500,flag:=1]
DT[,标志:=0]
DT[from=6500,标志:=1]
除非我不理解你的问题,否则结果应该是一样的。为什么不使用:
DT[, flag := +(from < 6500 & to > 6500)]
另一种可能性(由@Frank提出):
然而,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
库(微基准)
微基准(q=DT[,标志:=0][DT[,.I[6500%在%序列中(从,到,由=1)],由=1:nrow(DT)][[1]],标志:=1],
j1=DT[,标志:=+(从<6500到>6500)],
j2=DT[,标志:=ifelse(从<6500到>6500,1,0)],
j3=DT[,flag:=mapply(介于,6500,from,to之间)],
j4=DT[,标志:=介于(6500,从,到)]之间,
nikos=DT[,标志:=0][from=6500,标志:=1],
jimbo=DT[,标志:=6500=from])
单位:微秒
expr最小lq平均uq最大中值
q 2424842.4052498646.24952638230.47752545083.2020 2684601.62904336768.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
J4687.094731.7385877.6009780.1280858.38253073.322
尼科斯1077.9451186.23951424.41561290.70151389.85003699.621
金宝759.372 836.2075 1000.6322 884.4715 958.0035 3016.492
因此,最快的方法(j4中的between
选项)比问题中的原始方法快约3000倍。库(data.table)
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
种子(1)
DT表(DT$标志)
假真
5567 4433
试试帮助(“%between%”)
和帮助(“%chin%”)
如果你想问一个关于字符的问题,你应该这样做(作为一个新问题)。。。下面的所有答案似乎都能很好地处理您的示例。此外,它们将扩展到字符,因为字符之间的不平等很好,比如“6500”@Frank,我更新了我的帖子。很抱歉发帖时没有考虑周到。@Frank,我给出了一些想法,不认为我应该创建一个新问题,因为我的标题建议对数据进行子集设置。表
基于TRUE
/FALSE
。这就是我在解决方案中使用.I(…)
的原因。我最初的例子有误导性,所以我换了一个更相关的。“如果你不同意,请告诉我。”弗兰克说得通。我要问一个新问题。ifelse
要慢得多though@DavidArenburg这只是为了说明第一句话的作用谢谢你的详细解释。我想说我已经足够好了:)谢谢你公布时间安排。确实很有趣。您还可以将其简化为DT[,flag:=0][from=6500,flag:=1]
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
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