使用上面data.frame中的行和另一列计算值

时间:2019-03-31 23:26:55

标签: r dplyr

嗨,我想在R中做一些看起来应该很简单的事情,但是我似乎正在脑力衰退。

对于data.frame中的每一行,我想获取上一行中的Vol的值,为此行添加In的值,并减去一个依赖于该值的值。

这是我的尝试,但是滞后只是在开始时向后看一排值,一旦计算出下一个值,就不会继续往后看

library(dplyr)
df <- data.frame(In = c(1,4,0,0,1,2,3,0,0), Vol = c(1,rep(NA,8)))

df %>% mutate(Vol = (lag(Vol) + In) -  (lag(Vol) + In)*0.01)

所需的输出=

  In     Vol
1  1  1.00
2  4  4.95
3  0  4.90
4  0  4.85
5  1  5.79
6  2  7.72
7  3 10.61
8  0 10.50
9  0 10.40

5 个答案:

答案 0 :(得分:5)

这是使用accumulate软件包中的purrr的解决方案。 accumulate函数可以将具有两个参数(例如xy)的函数应用于向量序列。返回值将成为下一轮的输入值。

在下面的示例中,我要求accumulate函数从In列的第二个数字开始到结尾。我还为1参数提供了.init,它将成为函数的第一个x

library(dplyr)
library(purrr)

df <- data.frame(In = c(1,4,0,0,1,2,3,0,0), Vol = c(1,rep(NA,8)))

df %>% 
  mutate(Vol = accumulate(In[2:n()], function(x, y) (x + y) * 0.99, .init = 1))
#   In       Vol
# 1  1  1.000000
# 2  4  4.950000
# 3  0  4.900500
# 4  0  4.851495
# 5  1  5.792980
# 6  2  7.715050
# 7  3 10.607900
# 8  0 10.501821
# 9  0 10.396803

此外,似乎Vol列中的第一个值与In列中的第一个值相同。如果您只想在accumulate列上进行In处理,则下面的代码将更加简洁,甚至不需要将第一个值复制到{{1} }列。

Vol

答案 1 :(得分:2)

从上一行获取值并更新当前行中的值似乎是一项艰巨的任务。但是,mutate没有计算出的先前Vol值的“知识”,因为它会一起计算整个列的值。

在这种情况下,我们可以使用简单的for循环

for (i in 2:nrow(df)) {
   df$Vol[i] = (df$Vol[i-1] + df$In[i]) -  (df$Vol[i-1] + df$In[i])*0.01
}

df
#  In       Vol
#1  1  1.000000
#2  4  4.950000
#3  0  4.900500
#4  0  4.851495
#5  1  5.792980
#6  2  7.715050
#7  3 10.607900
#8  0 10.501821
#9  0 10.396803

数据

test = c(1, 4, 0, 0, 1, 2, 3, 0, 0)
df <- data.frame(In = test, Vol = c(1,rep(NA,8)))

答案 2 :(得分:2)

在这种情况下,您可以使用代数运算来表示所有Vol的第一个Vol

transform(df, Vol = c(df$Vol[1], sapply(2:NROW(df), function(n){
    0.99^(n-1) * df$Vol[1] + sum(0.99^((n-1):1) * df$In[2:n])
})))
#  In       Vol
#1  1  1.000000
#2  4  4.950000
#3  0  4.900500
#4  0  4.851495
#5  1  5.792980
#6  2  7.715050
#7  3 10.607900
#8  0 10.501821
#9  0 10.396803

答案 3 :(得分:2)

带有Reduce

的另一个选项
transform(df, 
          Vol = Reduce(function(x, y){
              x + y - 0.01 * (x + y)    
          },
          c(df$Vol[1], df$In[-1]),
          accumulate = TRUE))
#  In       Vol
#1  1  1.000000
#2  4  4.950000
#3  0  4.900500
#4  0  4.851495
#5  1  5.792980
#6  2  7.715050
#7  3 10.607900
#8  0 10.501821
#9  0 10.396803

答案 4 :(得分:2)

您还可以使用sapply基上的R来替换@Ronak的for循环。 invisible不是必需的功能,只是包裹在sapply周围即可使其安静地工作。

invisible(
  sapply(2:nrow(df), function(i) {
    df$Vol[i] <<- (df$Vol[i-1] + df$In[i]) -  (df$Vol[i-1] + df$In[i])*0.01
  }
         )
)

> df
  In       Vol
1  1  1.000000
2  4  4.950000
3  0  4.900500
4  0  4.851495
5  1  5.792980
6  2  7.715050
7  3 10.607900
8  0 10.501821
9  0 10.396803

微基准测试:

Unit: microseconds
            expr      min        lq      mean    median        uq       max neval
           tidy1  578.614  602.3825  736.8518  647.7345  792.1560  3409.963   100
           tidy2  566.256  601.1450 1524.3789  646.5240  801.3490 80219.732   100
        for.loop 4936.829 5288.2650 6007.9584 5635.4895 6540.4290  8982.346   100
          sapply  198.919  218.8710  305.8182  226.3600  243.1750  4489.870   100
 trans.db.reduce  127.456  149.8150  175.4649  172.6280  195.9935   292.835   100
        trans.db  217.416  236.1150  328.3348  255.2275  285.5560  5805.963   100