创建新的 R 数据框变量时使用前一行值

时间:2021-06-21 10:58:24

标签: r dataframe for-loop group-by lag

对于我的 R 数据框问题,我真的很感激。找不到类似的帖子,所以如果它已经存在,请分享!

我有以下数据:

mydata <- data.frame(inflow=c(50,60,55,70,80),
                     outflow=c(70,80,70,65,65),
                     current=c(100,100,100,100,100))

我想创建一个新列,它的作用类似于:

mutate(calc=pmax(lag(calc,default=current)+inflow-outflow,inflow))

它基本上创建了一个名为 calc 的新列,该列在 a) calc 的前一行值加上该行的流入减去流出或 b) 该行的流入值的最大值之间进行选择。 pmax 是一个名为 rmpfr 的包中的函数,它选择每行给定列中的最大值。

所以我的结果将是:row1 = max(100+50-70, 50) 即 80,row2 = max(80+60-80,60) 即 60,依此类推。

主要问题是滞后函数不允许采用您正在创建的同一列的前一行值,它必须是数据中已经存在的列。我想通过先创建 calc 列然后添加第二个计算步骤来分步完成,但无法完全解决。

最后,我知道使用 for 循环可能是一种解决方案,但想知道是否有不同的方法?我的数据按额外的列分组,并且不确定 for 循环是否适用于分组的数据行?

感谢您的帮助:)

2 个答案:

答案 0 :(得分:0)

也许 cummax 函数会有所帮助

mutate(calc=pmax(cummax(current+inflow-outflow),inflow))

答案 1 :(得分:0)

# I don't define the current column, as this is handled with the .init argument of accumulate2
mydata <- data.frame(
  inflow=c(50,60,55,70,80),
  outflow=c(70,80,70,65,65)
)

# define your recursive function
flow_function <- function(current, inflow, outflow){
  pmax(inflow, inflow - outflow + current)
}

mydata %>%
  mutate(result = accumulate2(inflow, outflow, flow_function, .init = 100)[-1] %>% unlist)

#   inflow outflow result
# 1     50      70     80
# 2     60      80     60
# 3     55      70     55
# 4     70      65     70
# 5     80      65     85

细节

purrr::accumulate 系列函数旨在执行递归计算。

accumulate 可以处理采用前一个值加上另一列中的值的函数,而 accumulate2 允许第二个附加列。您的情况属于后者。

accumulate2 需要以下参数:

  • .x - 计算的第一列。
  • .y - 计算的第二列。
  • .f - 要递归应用的函数:这​​应该有三个参数,第一个是递归参数。
  • .init -(可选)用作第一个参数的初始值。

所以在你的情况下,传递给 .f 的函数是

# define your recursive function
flow_function <- function(current, inflow, outflow){
  pmax(inflow, inflow - outflow + current)
}

我们首先测试这在 dplyr::mutate 之外产生了什么

# note I don't define the current column, as this is handled with the .init argument
mydata <- data.frame(
  inflow=c(50,60,55,70,80),
  outflow=c(70,80,70,65,65)
)


purrr::accumulate2(mydata$inflow, mydata$outflow, flow_function, .init = 100)
# returns
# [[1]]
# [1] 100
# 
# [[2]]
# [1] 80
# 
# [[3]]
# [1] 60
# 
# [[4]]
# [1] 55
# 
# [[5]]
# [1] 70
# 
# [[6]]
# [1] 85

所以关于返回值有两点需要注意:

  • 返回的对象是一个列表,所以我们要unlist返回一个向量。
  • 该列表有 6 个条目,因为它包含初始值,我们想删除它。

这两个最后的步骤在顶部的完整示例中汇总在一起。