我正在寻找一种有效的方法来对具有相同索引向量的两个向量进行子集化。有效的类别可以是:
假设我有两个向量
x
和 y
x <- 1:10
y <- 10:1
我想覆盖
x
的值与 y
的那些当x
小于 y
.我可以用(1)做到这一点:x[x < y] <- y[x < y]
但是这里我要写
x < y
两次,有错字的缺点是什么,在进行更新时,我可能会忘记在双方都这样做。所以我可以创建一个索引向量(2):idx <- x < y
x[idx] <- y[idx]
rm(idx)
但在这里我创建了一个额外的向量,它可能需要内存和时间。我也可以使用
for-loop
(3):for(i in seq_along(x)) {
if(x[i] < y[i]) x[i] <- y[i]
}
这可能很慢,我不知道
seq_along(x)
分配内存与否。我可以用
delayedAssign
在像(4)这样的环境中:(function() {
delayedAssign("idx", x < y)
x[idx] <<- y[idx]
})()
或 (5):
evalq({
delayedAssign("idx", x < y)
x[idx] <<- y[idx]}, envir = new.env(), enclos = parent.frame())
希望在哪里
delayedAssign
不会创建 idx
内存中的向量。基础中已经存在其他几种可能性,例如:x <- ifelse(x < y, y, x) #(6)
x <- sapply(seq_along(x), function(i) {if(x[i] < y[i]) y[i] else x[i]}) #(7)
with(data.frame(idx = x < y), x[idx] <<- y[idx]) #(8)
x < y
可以换成which(x < y)
什么可以减少矢量大小并改善execution time .最后,我对所有这些方法都不满意。
有没有推荐的方法用一个索引向量对两个向量进行子集化?对我来说,打字保存和内存消耗比执行时间更重要。
有没有办法在执行期间查看不同方法的内存消耗,例如使用
microbenchmark
查看执行时间,还是只能通过创建巨大的向量并查看系统进程来完成?
最佳答案
[…] But here I create an additional vector
不你不是。事实上,您创建的向量比之前的代码少一个,因为您只计算
x < y
一次而不是两次。顺便说一句,我会看到任何显式使用
rm
在代码中作为代码气味。相反,限制计算的范围,以便 idx
变量是短暂的。要明确地实现这一点,您可以使用 local
1:x = local({
idx = x < y
x[idx] = y[idx]
})
(但如图所示,这将需要重新分配给
x
,这会导致另一个 R 不太可能优化掉的副本;替代方法是通过 <<-
或 assign
在 local
调用中使用全局重新分配。 )[…] where I hope that
delayedAssign
does not create anidx
vector in memory
再次,是什么让你这么想?当然,它会在内存中创建一个向量——毕竟,您随后会使用它。您可能会认为计算是惰性执行的,但 R 最近通过 ALTREP 获得了此功能。 ,很少有这种表达式是自动创建的,它们在这里不相关。
1 您对
evalq
的使用是相似的,只是更复杂。 local
是 eval.parent(quote(…))
周围的便利包装器.
关于推荐使用相同索引向量对两个向量进行子集化的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56752595/