R генерирует значение ячейки на основе предыдущего значения ячейки в том же столбце

В настоящее время я занимаюсь моделированием на основе определенных данных. Конечная цель заключается в создании столбца, в котором первое значение основано на одной формуле, а затем второе, третье и четвертое значения основаны на предыдущем значении. (например, запись № 2 зависит от № 1, № 3 от № 2). Я решил эту проблему, запустив функцию мутации 3 раза. Однако, имея в виду аккуратность, я хотел бы либо иметь короткий цикл, либо использовать одну из функций применения для одновременного выполнения всех трех повторов. Какие-либо предложения?

Вот пример:

sampleframe <- data.frame("value1" = c(15,18,22,19),
                          "value2" = c(12,14,13,12),
                          "parameter" = c(0.8,NA,NA,NA))

sampleframe <- sampleframe %>%
  mutate("value3" = value2 * parameter)

Это генерирует кадр данных с первой строкой столбца value3 на основе одной формулы. Затем я хотел бы создать последние 3 строки. Я запускаю эту строку:

sampleframe <- sampleframe %>%
  mutate(`value3`= ifelse(is.na(value3) == FALSE,  value3,lag(value3) * value2))

который генерирует второе значение строки, сохраняя при этом значение первой строки. Затем мне нужно запустить одну и ту же команду еще два раза, чтобы заполнить последние 2 строки. Он работает в том смысле, что сохраняет предыдущие значения, всегда генерируя следующее, но кажется крайне неэффективным. Вернемся к моему вопросу, есть ли лучший способ сделать это? (предполагаю, что есть)

Изменить: учитывая решение для мурлыканья, я столкнулся со следующей проблемой при расширении моего приведенного выше примера. Если я хочу добавить константу в выражение, решение больше не работает:

sampleframe <- sampleframe %>%
  mutate(`value3`= ifelse(is.na(value3) == FALSE,  value3,lag(value3) * value2 + value 1))

В решении для мурлыканья:

sampleframe %>% 
  mutate(
    value3 = if_else(row_number() == 1, value2*parameter, value2),
    value3 = accumulate(value3, prod)
  )

Каждый член в значении3 будет умножать значение 2. Проблема в том, что добавление константы после значения 2:

sampleframe %>% 
  mutate(
    value3 = if_else(row_number() == 1, value2*parameter, value2 + value1),
    value3 = accumulate(value3, prod)
  )

Не дает желаемого результата, так как я не хочу, чтобы значение1 умножалось на значение2. Добавляем его во второй член:

sampleframe %>% 
  mutate(
    value3 = if_else(row_number() == 1, value2*parameter, value2),
    value3 = accumulate(value3, prod) + value1
  )

также не работает, потому что он добавляет value1 в качестве блока в самом конце, что означает, что строки 1 и 2 вычисляются правильно, а 3 и 4 — нет. Я пытался любым способом заставить эту команду работать, но я недостаточно знаком с пакетом purrr, чтобы найти исправление. Любые идеи?


person James    schedule 31.05.2021    source источник


Ответы (2)


Ограничивая мой ответ вашим текущим подходом, вы можете сделать вещи более эффективными, используя цикл for:

number_iterations = 3

# setup
sampleframe <- data.frame("value1" = c(15,18,22,19),
                          "value2" = c(12,14,13,12),
                          "parameter" = c(0.8,NA,NA,NA))

sampleframe <- sampleframe %>%
  mutate("value3" = value2 * parameter)

# run
for(ii = 1:number_iterations){
  sampleframe <- sampleframe %>%
    mutate(`value3`= ifelse(is.na(value3) == FALSE,  value3,lag(value3) * value2))
}

Четыре цикла будут обрабатывать запуск вашего кода столько раз, сколько вы укажете в number_iterations.

Тем не менее, я обычно рекомендую такие операции, как mutate, для одновременной работы со всем столбцом, а не для обновления одного значения за раз. Таким образом, вы, вероятно, получите дальнейшее повышение эффективности, исследуя различные структуры данных и подходы к решению.

person Simon.S.A.    schedule 01.06.2021
comment
Эй, спасибо за ответ, он отлично работает! Я был бы не против услышать идеи, если у вас есть какие-либо о том, как сделать это лучше. - person James; 01.06.2021

Вы можете использовать accumulate() из {purrr} и последовательно умножать числа.

sampleframe %>% 
  mutate(
    value3 = if_else(row_number() == 1, value2*parameter, value2),
    value3 = accumulate(value3, prod)
  )


#   value1 value2 parameter  value3
# 1     15     12       0.8     9.6
# 2     18     14        NA   134.4
# 3     22     13        NA  1747.2
# 4     19     12        NA 20966.4
person Zaw    schedule 01.06.2021
comment
Блестящий, работает как шарм. Благодарю вас! - person James; 01.06.2021
comment
Я пытался использовать команду «Накопить», когда хочу добавить еще один столбец, не умножая его в формуле, и почему-то не смог найти хороший способ сделать это. Я отредактировал свой вопрос, чтобы включить ваш ответ и сделать вопрос лучше отражающим мою проблему. - person James; 01.06.2021
comment
Возможно, добавить еще один оператор if_else для значения 1? Не уверен, что правильно вас понял. Во фрагменте я создаю значения 3, 4 и 5, чтобы показать шаги. Вы также можете объединить их, используя значение3. кадр выборки %›% мутировать(значение3 = если_еще(номер_строки() == 1, значение2*параметр, значение2), значение4 = накапливать(значение3, произведение), значение5 = если_еще(номер_строки() == 1, значение4, значение4 + значение2) ) - person Zaw; 01.06.2021