R根据同一列中的前一个单元格值生成一个单元格值

问题描述

我目前正在根据某些数据运行模拟。最终结果是生成一个列,其中第一个值基于一个公式,然后第二个、第三个和第四个值基于前一个值。 (例如,条目 n°2 取决于 n°1,n°3 取决于 n°2)我已经通过运行 mutate 函数 3 次解决了这个问题。但是,考虑到整洁,我想要一个短循环或使用应用函数之一一次执行所有 3 次重复。有什么建议吗?

这是一个例子:

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

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

这会根据一个公式生成带有“value3”列第一行的数据框。然后我想生成最后 3 行。我运行这一行:

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

生成第二行值,同时保留第一行值。然后我必须额外运行相同的命令两次才能填充最后 2 行。它的工作原理是在始终生成一个值的同时保留以前的值,但它似乎非常低效。回到我的问题,有没有更好的方法来做到这一点? (我假设有)

编辑: 鉴于 purrr 解决方案,我在扩展上面的示例时遇到了以下问题。如果我想在表达式中添加一个常量,该解决方案不再起作用:

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

在咕噜声解决方案中:

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

value3 中的每一项都会乘以 value 2。问题是在 value 2 后面加上常数:

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

不会产生想要的结果,因为我不希望 value1 乘以 value2。在第二项中添加

sampleframe %>% 
  mutate(
    value3 = if_else(row_number() == 1,prod) + value1
  )

也不起作用,因为它在最后添加了 value1 作为一个块,这意味着第 1 行和第 2 行计算正确,但第 3 行和第 4 行却没有。我尝试了任何我能想到的方法来使这个命令工作,但我对 purrr 包不够熟悉,无法找到修复方法。有什么想法吗?

解决方法

将我的回答限制在您当前的方法上,您可以通过使用 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))

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 这样的操作来一次处理整个列,而不是一次更新一个值。因此,您可能会通过研究不同的数据结构和解决方案来进一步提高效率。

,

您可以使用 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