推荐使用相同索引向量对两个向量进行子集化的方法

GKi*_*GKi 4 memory indexing performance r subset

我正在寻找一种有效的方法来对具有相同索引向量的两个向量进行子集化。有效类别可以是:

  • 错字保存
  • 内存消耗
  • 可读性
  • 计算时间

假设我有两个向量xy

x <- 1:10
y <- 10:1
Run Code Online (Sandbox Code Playgroud)

我想xywhen x小于的值覆盖的值y。我可以用(1)做到这一点:

x[x < y] <- y[x < y]
Run Code Online (Sandbox Code Playgroud)

但是在这里,我不得不写x < y两次,要写错字有什么缺点,当进行更新时,我会忘记在两边都这样做。所以我可以创建一个索引向量(2):

idx <- x < y
x[idx] <- y[idx]
rm(idx)
Run Code Online (Sandbox Code Playgroud)

但是在这里,我创建了一个额外的向量,它可能需要内存和时间。我也可以使用for-loop(3):

for(i in seq_along(x)) {
   if(x[i] < y[i]) x[i] <- y[i]
}
Run Code Online (Sandbox Code Playgroud)

这可能很慢,我不知道是否seq_along(x)分配内存。我可以delayedAssign在(4)之类的环境中使用:

(function() {
  delayedAssign("idx", x < y)
  x[idx] <<- y[idx]
})()
Run Code Online (Sandbox Code Playgroud)

或(5):

evalq({
  delayedAssign("idx", x < y)
  x[idx] <<- y[idx]}, envir = new.env(), enclos = parent.frame())
Run Code Online (Sandbox Code Playgroud)

我希望这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)
Run Code Online (Sandbox Code Playgroud)

x < y可以替换为which(x < y)可以减小向量大小并缩短执行时间的函数。

最后,我对所有这些方法都不满意。

有没有建议的方法来用一个索引向量将两个向量子集化?对我而言,错字保存内存消耗执行时间更重要。

有没有办法查看执行过程中不同方法的内存消耗,例如microbenchmark用来查看执行时间,还是只能通过创建巨大的向量并查看系统进程来完成?

Kon*_*lph 6

[…]但是在这里我创建了一个附加向量

不你不是。实际上,您创建的向量比以前的代码少,因为您只计算x < y一次而不是两次。

顺便说一句,我会看到rmin 显式使用in作为代码味道。相反,请限制计算范围,以使idx变量寿命短。要明确实现这一点,可以使用local1

x = local({
    idx = x < y
    x[idx] = y[idx]
})
Run Code Online (Sandbox Code Playgroud)

(但是如图所示,这将需要重新分配,x这会导致R不太可能优化掉的另一个副本;替代方法是通过调用<<-assignlocal调用内部使用全局重新分配。)

[…]我希望delayedAssign不要idx在内存中创建向量

再次,您怎么认为呢?当然,它会在内存中创建一个向量-毕竟,您随后会使用它。您可能会认为计算是延迟执行的,但是尽管R最近通过ALTREP获得了此功能,但很少有情况会自动创建此类表达式,因此在这里与它们无关。

1您的用法evalq类似,只是更加复杂。local是一个方便包装eval.parent(quote(…))