在R中,如何在不使用循环的情况下进行迭代计算?

在R中,如何在不使用循环的情况下进行迭代计算?,r,loops,iteration,shift,R,Loops,Iteration,Shift,下面是一种迭代计算的简单示例: vals <- data.frame( "x"=c( 14, 15, 12, 10, 17 ), "ema"=0 ) vals$ema[1] <- vals$x[1] K <- 0.90 for( jj in 2:nrow( vals ) ) vals$ema[jj] <- K * vals$ema[jj-1] + (1-K) * vals$x[jj] vals x ema 1 14 14.0000 2 15 14.10

下面是一种迭代计算的简单示例:

vals <- data.frame( "x"=c( 14, 15, 12, 10, 17 ), "ema"=0 )
vals$ema[1] <- vals$x[1]
K <- 0.90
for( jj in 2:nrow( vals ) )
  vals$ema[jj] <- K * vals$ema[jj-1] + (1-K) * vals$x[jj]

vals
   x     ema
1 14 14.0000
2 15 14.1000
3 12 13.8900
4 10 13.5010
5 17 13.8509
vals似乎成功了:

vals$ema2 <- c(vals$ema[1], K*vals$ema[1:4] +(1-K)*vals$x[2:5] )

> vals
   x     ema    ema2
1 14 14.0000 14.0000
2 15 14.1000 14.1000
3 12 13.8900 13.8900
4 10 13.5010 13.5010
5 17 13.8509 13.8509
VAL$ema2 VAL
x ema ema2
1 14 14.0000 14.0000
2 15 14.1000 14.1000
3 12 13.8900 13.8900
4 10 13.5010 13.5010
5 17 13.8509 13.8509

有时最好使用时间序列和数据挖掘库。在这种情况下,zoo库中的lag.zoo将为您处理滞后值

library(dplyr)
library(zoo)
vals <- data.frame( "x"=c( 14, 15, 12, 10, 17 ) )
K <- 0.90
vals %>% mutate(ema = (1-K)*vals$x + K*(lag(vals$x,1)))
库(dplyr)
图书馆(动物园)

VAL对于这个特殊问题,每个值的权重是
k
i
的函数(如
i
第h个值)。我们可以为权重编写一个函数,并将其矢量化:

weights <- function(i, k) {
    q <- 1-k
    qs <- '^'(q, 1:i)
    rev(qs) * c(1, rep(k, (i-1)))
}
v_weights <- Vectorize(weights)
其中,这些是“之前”值的权重。我们继续学习一些矩阵代数。我编写了一个函数,使权重(如上)成为一个矩阵:

weight_matrix <- function(j, k) {
    w <- v_weights(1:j, k=k)
    Ws <- matrix(0, j+1, j+1)
    Ws[row(Ws)+col(Ws)<(j+2)] <- unlist(rev(w))
    Ws <- t(Ws)
    Ws[row(Ws)+col(Ws)==(j+2)] <- k
    Ws[(j+1),1] <- 1
    Ws
}

然后将其与
x
s的向量相乘。功能:
ema@shayaa的答案99%正确
dplyr
实现了
lag
很好,除了答案中的输入错误(x
的一个值应该是
ema
),对列名的额外调用,以及缺少的默认值(否则它会将
NA
放在第一行)之外,它工作得非常好

library(dplyr)
vals %>% mutate(ema = K*lag(ema, 1, default=ema[1]) + (1-K)*x)
#>    x     ema
#> 1 14 14.0000
#> 2 15 14.1000
#> 3 12 13.8900
#> 4 10 13.5010
#> 5 17 13.8509
WaltS的这篇文章为我提出的关于递归计算的类似问题提供了两种可能的解决方案。根据您的问题调整其中一项:

vals$ema.Reduce <- Reduce(function(myema, x) K * myema + (1-K) * x, 
                          x =  tail(vals$x, -1), init = 14, accumulate = TRUE)
vals
#   x     ema ema.Reduce
#1 14 14.0000    14.0000
#2 15 14.1000    14.1000
#3 12 13.8900    13.8900
#4 10 13.5010    13.5010
#5 17 13.8509    13.8509

或者说
vals$ema2他们希望你替换的循环中的OP(令人困惑地)重写了ema;它实际上从14开始一直向下(如果您运行代码直到for循环之前)。这两个引用VAL$ema的答案都引用了计算VAL$ema2的答案。我只想引用VAL$x——或者以前没有计算过的ema值。这不起作用:VAL$ema2这不起作用。在方程式的1-K和K部分中都使用VAL$x。这是一个迭代计算:1-K部分应该使用之前计算的ema值。因为我收到的答案都没有解决问题,所以我去查看TTR包,哪个是EMA,它比R中的循环做得更快。TTR做的是进入C并在那里循环:我的问题仍然是一样的:你能不使用循环在R中进行迭代计算吗?值得学习
base
R,然后再到处建议重载
dplyr
。我不同意。仅仅因为
base
首先存在,并不能使它成为每个工作的更好工具。这并不是很重,而且大大简化了答案。你的答案中有错误吗?当我遇到:>vals x ema 1142 15 0 3 12 0 4 10 0 5 17 0时,我得到的答案是:x ema 1144.0 2 15 14.1 3 12 1.2 4 10 1.0 5 17 1.7。似乎您首先预加载了ema列。您的代码使用ema的旧值,除第一个插槽外,该值以零开始。据我所知,这是行不通的。这是一个有趣的想法,但有点复杂。如何将其应用于更复杂的示例,在这些示例中,在计算出之前的值之前,您不知道要应用的因子?大多数工作是将矩阵转换为正确的形式,否则它只是线性代数。仔细考虑后,我认为您最初的问题——如何在不使用循环的情况下进行迭代计算——实际上取决于您想要进行的具体计算,因此每个解决方案都将是相当定制的。我确实认为我对您最简单的示例的解决方案是这里唯一满足您要求的解决方案,即“我只想参考
vals$x
——或之前未计算的ema值。”:)建议了向量化可能特别有利可图的实例。我确实认为这里的其他一些答案非常优雅和实用,即使有隐含的循环。我认为这正是我所寻找的。谢谢你的详细答复。我不知道LISP称之为Reduce,但如果我要求折叠或累积,可能有人会更快地回答。
weight_matrix <- function(j, k) {
    w <- v_weights(1:j, k=k)
    Ws <- matrix(0, j+1, j+1)
    Ws[row(Ws)+col(Ws)<(j+2)] <- unlist(rev(w))
    Ws <- t(Ws)
    Ws[row(Ws)+col(Ws)==(j+2)] <- k
    Ws[(j+1),1] <- 1
    Ws
}
> weight_matrix(3, .1)
      [,1]  [,2] [,3] [,4]
[1,] 0.729 0.081 0.09  0.1
[2,] 0.810 0.090 0.10  0.0
[3,] 0.900 0.100 0.00  0.0
[4,] 1.000 0.000 0.00  0.0
> x <- c(14, 15, 12, 10, 17)
> k <- .1
> vals <- data.frame("x"=x, "ema"=ema(x, k))
> vals
   x     ema
1 14 14.0000
2 15 14.1000
3 12 13.8900
4 10 13.5010
5 17 13.8509
library(dplyr)
vals %>% mutate(ema = K*lag(ema, 1, default=ema[1]) + (1-K)*x)
#>    x     ema
#> 1 14 14.0000
#> 2 15 14.1000
#> 3 12 13.8900
#> 4 10 13.5010
#> 5 17 13.8509
vals$ema.Reduce <- Reduce(function(myema, x) K * myema + (1-K) * x, 
                          x =  tail(vals$x, -1), init = 14, accumulate = TRUE)
vals
#   x     ema ema.Reduce
#1 14 14.0000    14.0000
#2 15 14.1000    14.1000
#3 12 13.8900    13.8900
#4 10 13.5010    13.5010
#5 17 13.8509    13.8509
Reduce(function(myema, x) {
    if(myema < 5) {
      5
    } else if(myema > 15) {
      15
    } else {
      K * myema + (1-K) * x
    }
  }, x =  tail(vals$x, -1), init = 16, accumulate = TRUE)
#[1] 16.000 15.000 14.700 14.230 14.507

Reduce(function(myema, x) {
    if(myema < 0) {
      K1 * myema + (1-K1) * x
    } else if(myema > 100) {
      K3 * myema + (1-K3) * x
    } else {
      K2 * myema + (1-K2) * x
    }
  }, x =  tail(vals$x, -1), init = 110, accumulate = TRUE)
#[1] 110.00000 100.50000  91.65000  87.56750  84.03912

K3*110     + (1-K3)*vals$x[2] #100.5
K3*100.5   + (1-K3)*vals$x[3] #91.65
K2*91.65   + (1-K2)*vals$x[4] #87.5675
K2*87.5675 + (1-K2)*vals$x[5] #84.03912