2016-07-28 4 views
0

Вот простой пример одного типа итерационного известково:В R, как мне сделать итеративный расчет без использования цикла?

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 

Более привлеченными примеры использования, если ... то еще, чтобы определить следующее значение:

for(jj in 2:nrow(vals)) 
    if(K * vals$ema[jj-1] + (1-K) * vals$x[jj] < 5.0) 
     vals$ema[jj] <- 5.0 
    else if(K * vals$ema[jj-1] + (1-K) * vals$x[jj] > 15.0) 
     vals$ema[jj] <- 15.0 
    else 
     vals$ema[jj] <- K * vals$ema[jj-1] + (1-K) * vals$x[jj] 

Я не уверен, если это будет более участвовать или нет, но решение может быть основано на предыдущем значении, а также:

K1 <- 0.999 
K2 <- 0.95 
K3 <- 0.90 
for(jj in 2:now(vals)) 
    if(vals$ema[jj-1] < 0.0) 
     vals$ema[jj] <- K1 * vals$ema[jj-1] + (1-K1) * vals$x[jj] 
    else if(vals$ema[jj-1] > 100.0) 
     vals$ema[jj] <- K3 * vals$ema[jj-1] + (1-K3) * vals$x[jj] 
    else 
     vals$ema[jj] <- K2 * vals$ema[jj-1] + (1-K2) * vals$x[jj] 
+0

Так как ни один из ответов я получил решить эту проблему, я пошел искать в TTR пакет, который делает EMA, и он делает их быстрее, чем цикл в R. Что делает TTR, это падение на C и цикл там: https://github.com/joshuaulrich/TTR/blob/master/src/moving_averages.c Мой вопрос все равно: вы можете сделать итеративный расчет в R без использования цикла? –

ответ

0

Кажется это удается:

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 
+0

или say 'vals $ ema2 <- c (vals $ ema [1], K * vals $ ema [1: (nrow (vals) -1)] + (1-K) * vals $ x [2: nrow (vals)]) ' – abhiieor

+0

OP (смущающе) перезаписал ema в цикле, который они хотят, чтобы вы заменили; он действительно начинается с 14 на всем пути вниз (если вы запустите код до самого цикла for). – Frank

+0

Оба этих ответа, которые относятся к vals $ ema, относятся к ответу для вычисления vals $ ema2. Я хочу ссылаться только на vals $ x - или значение ema, которое ранее не рассчитывалось. –

0

Иногда лучше работать с временными рядами и библиотеками сбора данных. В этом случае lag.zoo из библиотеки 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))) 
+0

Это не работает. Вы используете vals $ x как в 1-K, так и в K-части уравнения. Это итеративный расчет: 1-K часть должна использовать ранее вычисленное значение ema –

0

Для этой конкретной задачи, вес для каждого значения некоторой функция k и i (как в i го значения). Мы можем написать функцию для весов, и векторизации его:

weights <- function(i, k) { 
    q <- 1-k 
    qs <- '^'(q, 1:i) 
    rev(qs) * c(1, rep(k, (i-1))) 
} 
v_weights <- Vectorize(weights) 

пример:

> v_weights(1:3, .1) 
[[1]] 
[1] 0.9 

[[2]] 
[1] 0.81 0.09 

[[3]] 
[1] 0.729 0.081 0.090 

, где они весов «предыдущих» x значений. Перейдем к некоторой матричной алгебре. Я пишу функцию, чтобы сделать веса (выше) в матрицу:

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 с. Функция: ema <- function(x, k) rev(weight_matrix(length(x)-1, k) %*% x[1:(length(x))]).

Чтобы получить dataframe выше (я "щелкнул" k так что 0,1 вместо 0,9):

> 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 
+0

Это интересная идея, но немного сложная. Как бы вы применили ее к более вовлеченным примерам, где вы не знаете, какой фактор применять до тех пор, пока вы не рассчитали предыдущее значение? –

+0

Большая часть работы - это перебор матрицы в правой форме - иначе это просто линейная алгебра. Подумав об этом немного, я думаю, что ваш первоначальный вопрос - как сделать итеративный расчет без использования цикла - действительно зависит от конкретного расчета, который вы хотите сделать, поэтому каждое решение будет довольно на заказ. Я думаю, что мое решение для вашего простого примера - единственное один из которых удовлетворяет вашему требованию: «Я хочу ссылаться только на« vals $ x »- или значение ema, которое ранее не рассчитывалось». :) –

+0

[This article] (http://www.noamross.net/ blog/2014/4/16/vectorization-in-r - why.html) предлагает примеры, в которых векторизация может быть особенно прибыльной. Я действительно думаю, что некоторые из других ответов здесь довольно элегантны и функциональны, хотя есть неявный цикл. –

0

@ ответ 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 
+0

Стоит изучить 'base' R, прежде чем предлагать тяжелый' dplyr' всюду. –

+1

Я почтительно не согласен. Просто потому, что «base» был там первым, он не делает его лучшим инструментом для каждой работы. Это вряд ли тяжело и значительно упрощает ответ. –

+0

Есть ли ошибка в вашем ответе? Когда я бегу против:> vals x ema 1 14 14 2 15 0 3 12 0 4 10 0 5 17 0 Получаю ответ: x ema 1 14 14.0 2 15 14.1 3 12 1.2 4 10 1.0 5 17 1.7. Кажется, что вы предварительно загрузили столбец ema. В вашем коде используются старые значения ema, которые начинаются как ноль, за исключением первого слота. Из того, что я могу сказать, это не работает. –

1

Это answer по 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 

Объяснение функции:

Reduce() является вычисление EMA для текущей строки JJ и myema является предыдущее значение (JJ-1), начиная с init ,x вектор, требуемый Reduce, состоит из vals $ x для строк, которые вы хотите вычислить: строка 2 до последней строки = x = tail(vals$x, -1). Опция accumulate = TRUE возвращает вектор вместо конечного значения. (Обратите внимание, что x термин в Reduce является общим термином и не совпадает с vals $ x в данных примера. Для вычислений, которые не требуют дополнительного термина vals $ x, будет работать вектор из 0 (как в связанном ответ)).

Добавление если/другое условия к Reduce (примечание: init изменяется в этих примерах, чтобы проиллюстрировать условные операторы):

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 
+0

Я думаю, это именно то, что я искал. Благодарим вас за подробный ответ. Я не знал, что LISP назвал это сокращением, но, может быть, если бы я попросил Fold или Accumulate, кто-то мог бы ответить раньше. –

Смежные вопросы