在R中向量化迭代函数的最佳方法是什么?

时间:2019-01-26 22:00:07

标签: r vectorization data-science

我正在使用一个引用给定人组合价值的函数。要使用此功能,我需要遍历数据框的行并应用此功能:

x$cota <- 100

cotiza <- function(x){
  for(i in 1:nrow(x)) {
    if (i > 1){
      x[i,]$cota <- ((x[i,]$pl - x[i,]$mov)/x[i-1,]$pl) * x[i-1,]$cota
    }
  return (x)
}

这是该函数应用于的数据框:

    data    pl     mov cota
1 2018-01-01 500.0  250000  100
2 2018-01-02 525.0       0  100
3 2018-01-03 997.2 -100000  100
4 2018-01-04 500.0       0  100
5 2018-01-05 520.0       0  100

此数据帧上函数的输出应类似于:

    data    pl     mov     cota
1 2018-01-01 500.0  250000   100.00
2 2018-01-02 525.0       0   105.00
3 2018-01-03 997.2 -100000 20199.44
4 2018-01-04 500.0       0 10128.08
5 2018-01-05 520.0       0 10533.20

反正有功能使该函数向量化,以便可以将其应用于数据框吗?

2 个答案:

答案 0 :(得分:3)

由于cota[3]依赖于cota[2]的更新后的值cota[1],因此您无法对该函数进行简单的矢量化。有时,您可以通过使用cumsumcumprod或类似的累积函数(仍然是迭代的,但是在真正优化的代码中)作弊,但它依赖于“简单的迭代累积”。但是,在这种情况下,

cota[2] = cota[1] * (pl[2] - mov[2]) / pl[1],
cota[3] = cota[2] * (pl[3] - mov[3]) / pl[2]

如果替换cota[2],您会得到

(cota[1] * (pl[2] - mov[2]) / pl[1]) * (pl[3] - mov[3]) / pl[2]

有效

cota[1] * (pl[2]*pl[3] - pl[2]*mov[3] - pl[3]*mov[2] + mov[2]*mov[3]) / (pl[1] * pl[2])

不会立即将其借给简单的累积运算符。

一些函数提供了各种滚动窗口,特别是zoo::rollapply,但是它们经常在幕后进行for循环。 (从技术上讲,我相信大多数*apply函数也在内部进行for循环,尽管可能在内部进行 well 。)

如果您对此功能或类似功能有性能问题,则可以始终使用Rcpp或类似的加速方法。 (一旦进入Rcpp区域,您可能会发现原始的for循环会击败矢量化代码,甚至是Rcpp原生矢量化,尽管这在很大程度上取决于许多其他因素。 )

答案 1 :(得分:2)

1)使用最后在注释中可重复显示的输入,尝试使用cumprod,如下所示:

cotiza2 <- function(x) {
  n <- nrow(x)
  if (n < 2) return(x)
  transform(x, cota = cumprod(c(cota[1], (pl - mov)[-1] / pl[-n])))
}

cotiza2(x)
##         data    pl     mov     cota
## 1 2018-01-01 500.0  250000   100.00
## 2 2018-01-02 525.0       0   105.00
## 3 2018-01-03 997.2 -100000 20199.44
## 4 2018-01-04 500.0       0 10128.08
## 5 2018-01-05 520.0       0 10533.20

2)这不是矢量化的,但是比问题中的代码短,并且比(1)的技巧少。

cotiza3 <- function(x) {
  n <- nrow(x)
  if (n < 2) return(x)
  within(x, for(i in 2:n) cota[i] <- (pl[i] - mov[i]) / pl[i-1] * cota[i-1])
}

cotiza3(x)
##         data    pl     mov     cota
## 1 2018-01-01 500.0  250000   100.00
## 2 2018-01-02 525.0       0   105.00
## 3 2018-01-03 997.2 -100000 20199.44
## 4 2018-01-04 500.0       0 10128.08
## 5 2018-01-05 520.0       0 10533.20

注意

Lines <- "
    data    pl     mov cota
1 2018-01-01 500.0  250000  100
2 2018-01-02 525.0       0  100
3 2018-01-03 997.2 -100000  100
4 2018-01-04 500.0       0  100
5 2018-01-05 520.0       0  100"
x <- read.table(text = Lines)

更新

添加了(1)。