我在R [300000,45]中有一个较大的数据框。我想添加一个TRUE / FALSE列(或创建一个向量),如果另一列的值不同于上面的值(i-1),则分配TRUE,如果它们相同则为FALSE。基本的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函数是更快还是更有效,因为已经分配了大小和类型。
答案 0 :(得分:3)
利用矢量化。像下面这样的东西可以解决这个问题:
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
答案 1 :(得分:2)
您可以使用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
因此,使用您的datasize,处理时间应小于一秒。请注意,这些时间包括创建测试数据集,因此实际差异几乎快两倍。
与基于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倍。