оптимизация итерационных вычислений, позволяющая избежать циклов на R

Мне нужно применить итеративный расчет к строкам data.frame в R. Проблема в том, что для каждой строки результат зависит от результатов предыдущего расчета и предыдущих строк.

Я реализовал решение, используя цикл, подобный следующему примеру:

example <- data.frame(flag_new = c(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE),
                      percentage =sample(1:100,22)/100)
n.Row <- nrow(example)

# initialization
example$K <-0
example$R <-0
example$K[1] <-100
example$R[1] <-example$K[1]*example$percentage[1]

#loop
for(i in 2:n.Row){
  if(example$flag_new[i]){
    example$K[i] <-100

  } else {
    example$K[i] <-example$K[i-1]-example$R[i-1]
  }
  example$R[i] <- example$K[i]*example$percentage[i]
}

Проблема в том, что реальный код очень медленный (особенно если я использую его в фрагменте R на KNIME)

Есть ли способ оптимизировать код более эффективным способом, подобным R? Я пытался использовать семейство приложений, но в моем случае это не сработало.

Большое спасибо


person Luca Monno    schedule 19.01.2017    source источник


Ответы (1)


Вот попытка data.table с использованием совокупного flag_new для группировки

set.seed(1)
example <- data.frame(flag_new = c(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE),
                      percentage =sample(1:100,22)/100)    

# initialization
initK = 100

# Copy to allow comparison to your code
newd = example

library(data.table)
setDT(newd)[, Knew:= initK* c(1, cumprod(1 - percentage[-.N])), 
                              by=cumsum(flag_new)][, Rnew:=Knew* percentage]

Сравните с результатами после запуска цикла в вашем вопросе

all.equal(example$K, newd$Knew) 
all.equal(example$R, newd$Rnew)

Группируя вычисления, которые необходимо выполнить от первого TRUE до следующего, вычисления можно выполнять без цикла.

Например, используя первую группу, расчет может быть выполнен как

d = example[1:8, ]
d$K1 <- d$K* c(1, cumprod(1 - d$percentage[-length(d$percentage)]))
d$R2 <- with(d, K1* percentage)

Это происходит от того, как

k[i] = k[i-1] - R[i-1] 
k[i] = k[i-1] - k[i-1]* p[i-1] 
     = k[i-1](1 - p[i-1])
So 
k[2] = k[1]* (1-p[1])
k[3] = k[2]* (1-p[2]) = k[1]* (1-p[1])* (1-p[2])
k[4] = k[3]* (1-p[3]) = k[1]* (1-p[1])* (1-p[2])* (1-p[3])
and so on..

Так что просто нужен метод разделения, применения, объединения, чтобы рассчитать их для каждой группы, для которой я использовал data.table

person user20650    schedule 19.01.2017
comment
Большое спасибо @user20650. Это помогает для хорошей части моей проблемы. Этот пример был упрощением более крупной проблемы. Что, если у меня есть что-то вроде этого: 'example$K[i] ‹-f(example$K[i-1],example$R[i-1])' и 'example$R[i] ‹- g( пример$K[i],пример$процентов[i])' - person Luca Monno; 20.01.2017
comment
Я думаю, это будет зависеть от того, каковы функции f и g. Можете ли вы отредактировать свой вопрос с помощью небольшого примера, включая функции, которые воспроизводят вашу реальную проблему, пожалуйста (с кодом, показывающим ожидаемый результат, как и раньше) - person user20650; 20.01.2017