Решение Mapply или Lapply вместо итеративного цикла for, который последовательно отклоняет значения от разных значений одного и того же вектора - PullRequest
1 голос
/ 05 марта 2019

Попытка выучить лучшие решения, чем циклы for, и почувствовать, что этот экземпляр может пригодиться для неудовлетворенности или мапплинга.

У меня есть кадр данных из двух столбцов (тома, месяцы. Пройденный) из разных моментов времени.Я уменьшаюсь по вектору значений спада (fall.vector), в результате чего начальная точка снижения изменяется в зависимости от месяца, прошедшего + 1 месяц, до конца fall.vector.

В настоящее время мое решение, котороеотлично работает, это:

decline.vector <- c( 0.9,0.81,0.729,0.656,0.590,0.531,0.478, 0.430, 0.387,0.348)
months.passed <- c(2,4,5,6)
volumes <- c(10,20,10,20)
df <- data.frame(months.passed, volumes)

for(i in 1:nrow(df)) {
    build <- df$volumes[i] * cumprod(decline.vector[df$months.passed[i]+1:nrow(decline.vector),])
    build <- rbind(final,build)
}

return(build)
    [1] NA  NA  7.29    6.56    5.90    5.31    4.78    4.30    3.87    3.49
    [2] NA  NA  NA  NA  11.81   10.63   9.57    8.61    7.75    6.97
    [3] NA  NA  NA  NA  NA  5.31    4.78    4.30    3.87    3.49
    [4] NA  NA  NA  NA  NA  NA  9.57    8.61    7.75    6.97

Есть ли более элегантный способ сделать это, используя lapply или mapply, или даже что-то вместо rbind?

1 Ответ

0 голосов
/ 06 марта 2019

Вот вариант с использованием mapply

out1 <- t(mapply(
  function(x, y, z = decline.vector) {
    n <- length(z)
    c(rep(NA, y), x * z[(y + 1):n]) 
  },
  x = volumes,
  y = months.passed
))
out1
#     [,1] [,2] [,3] [,4] [,5]  [,6] [,7] [,8] [,9] [,10]
#[1,]   NA   NA 7.29 6.56  5.9  5.31 4.78  4.3 3.87  3.48
#[2,]   NA   NA   NA   NA 11.8 10.62 9.56  8.6 7.74  6.96
#[3,]   NA   NA   NA   NA   NA  5.31 4.78  4.3 3.87  3.48
#[4,]   NA   NA   NA   NA   NA    NA 9.56  8.6 7.74  6.96

Векторизованный вариант, в котором мы используем матричное умножение

out2 <- t(t(volumes)) %*% t(decline.vector)

Далее мы используем матрицу для вставки NA с в первые months.passed столбцы для каждой строки

out2[cbind(rep(1:length(months.passed), months.passed),
           sequence(months.passed))] <- NA

Результат

identical(out1, out2)
# [1] TRUE

данные

decline.vector <- c(0.9, 0.81, 0.729, 0.656, 0.590, 0.531, 0.478, 0.430, 0.387, 0.348)
volumes <- c(10, 20, 10, 20)
months.passed <- c(2, 4, 5, 6)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...