[英]Faster way to make this ifelse loop in r
我在R [300000,45]中有一个比较大的数据帧。 我想添加一个TRUE / FALSE的列(或创建一个向量),如果另一列的值不同于上面的(i-1)和FALSE的值相同,则分配TRUE。 基本的R代码为:
etS$ar1TF <- NA
mode(etS$ar1TF) <- 'logical'
etS$ar1TF[1] <- TRUE
for(i in 2:length(etS$ar1TF)) {
if(etS$siteYear[i] == etS$siteYear[i-1]) {
etS$ar1TF[i] <- FALSE
} else {
etS$ar1TF[i] <- TRUE
}
}
但是,这将非常缓慢且效率低下。 是否有更好的方法使用现有功能或向量化来快速有效地完成此任务? 我不确定while()
语句是否会更有效。 我想我可以先将所有内容赋为TRUE,然后在for循环中使用if语句并删除else
语句,但这确实没有什么好。 我不确定在这种情况下apply函数是否会更快或更有效,因为已经分配了大小和类型。
利用向量化。 如下所示将达到目的:
ar1TF <- logical(length(siteYear))
ar1TF[-1] <- (siteYear[-1] != siteYear[-length(siteYear)])
ar1TF[1] <- NA
etS$ar1TF <- ar1TF # to add the column to the data.frame
编辑 :似乎diff
解决方案可能会快一点:
x <- sample(1:3, 100000, replace=TRUE)
library('microbenchmark')
microbenchmark({
y1 <- logical(length(x))
y1[-1] <- (x[-1] != x[-length(x)])
y1[1] <- NA
},{
y2 <- diff(x)
y2 <- c(NA, y2 != 0)
})
## Unit: microseconds
## expr min lq median uq max neval
## [!=] 1062.651 1070.690 1088.1935 1169.500 2367.582 100
## [diff] 811.121 821.443 844.3575 892.967 2244.022 100
您可以使用diff
执行区别:
vec = sample(1:10, 100, replace = TRUE)
diff(vec) == 0
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[25] FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[37] FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
[49] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
[61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE
[73] FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[85] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[97] FALSE FALSE FALSE
diff
的标准设置使用1的滞后量。 要将其添加到data.frame
,您需要附加一个NA
:
df$new_col = c(NA, diff(vec) == 0)
一些基本的时序表明,对于较大的向量,这也非常快:
> system.time(dum <- diff(sample(1:10, 10e3, replace = TRUE)) == 0)
user system elapsed
0.001 0.000 0.001
> system.time(dum <- diff(sample(1:10, 10e5, replace = TRUE)) == 0)
user system elapsed
0.189 0.012 0.202
> system.time(dum <- diff(sample(1:10, 10e7, replace = TRUE)) == 0)
user system elapsed
6.810 1.908 10.376
因此,使用您的数据大小,处理时间应少于一秒。 请注意,这些时间包括创建测试数据集,因此实际差异几乎快两倍。
与基于for
循环的解决方案进行直接比较显示出速度差异:
diff_for_loop = function(vec) {
result_vec = vec
for(i in seq_along(vec)[-1]) {
if(vec[i] == vec[i-1]) {
result_vec <- FALSE
} else {
result_vec <- TRUE
}
}
return(result_vec)
}
vec = sample(1:10, 10e5, replace = TRUE)
system.time(dum_for_loop <- diff_for_loop(vec))
# user system elapsed
# 1.220 0.008 1.232
system.time(dum_diff <- diff(vec) == 0)
# user system elapsed
# 0.051 0.005 0.056
这使得基于diff
的解决方案快了22倍。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.