Решение Mapply или lapply вместо итеративного цикла for, который последовательно уменьшает значения относительно разных значений одного и того же вектора

#r

#r

Вопрос:

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

У меня есть фрейм данных из двух столбцов (объемы, месяцы.пройдено) из разных моментов времени, я уменьшаю по вектору значений снижения (declease.vector), при котором точка начала снижения изменяется в зависимости от пройденного месяца 1 месяц, до конца declease.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 or mapply , либо даже что-то вместо rbind?

Комментарии:

1. Цикл for у меня не работает, поскольку ваш код, похоже, предполагает, что decline.vector это матрица или фрейм данных, а не вектор, который вы предоставляете, среди прочих проблем. Я могу исправить их и получить результат, аналогичный тому, который вы предоставляете, но без реального воспроизводимого примера невозможно узнать формат, который вы ожидаете, что было бы необходимо для предоставления вам более полезной информации.

2. Тай дивибисан, не осознавал, что я на самом деле выбираю decline.vector из фрейма данных, используя dplyr в моем реальном коде, не думал, что это будет иметь значение здесь для примера, но вижу, что это имеет значение.

Ответ №1:

Вот вариант, использующий 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 s в первые 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)
  

Комментарии:

1. Это потрясающе, спасибо тебе за это, Маркус, несмотря на недостаток моего воспроизводимого примера.