根据尚不存在的列创建一个新列。

8

我有以下数据集:

DT <- fread("   df1 df2
  1   8
  2   9
  3  10
  4  11
  5  12")

我希望创建一个新的列 df3,首个值为100,然后是公式 lag(df3, 1) * (1 + df2)。最终输出结果如下:

df1 df2     df3
1  1  8     100
2  2  9    1000
3  3 10   11000
4  4 11  132000
5  5 12 1716000

我尝试运行DT[,df3 := lag(df3, 1) * (1 + df2)],但由于df3还不存在,所以我收到了错误提示。

该语句涉及到IT技术相关内容,其中DT[,df3 := lag(df3, 1) * (1 + df2)]是一段代码。因为df3还未存在,所以会导致错误。
2个回答

8

我将早先的答案保留下来,因为它取得了一定的成功,但是我忽视了使用 cumprod 会更快:

DT$df3 <-  100 * cumprod(c(0,DT$df2[-1])+1)        # base R
DT[, df3:= 100 * cumprod(c(0,df2[-1])+1)]          # data.table
DT %>% mutate(df3 = 100 * cumprod(c(0,df2[-1])+1)) # tidyverse (only dplyr here)

我们计算df2+1的累积乘积,忽略第一个元素并从1开始,并将其乘以100

使用Reduce函数的先前答案:

这是Reduce函数的一个很好的应用场景,我们使用简单的乘法函数,然后确保执行以下操作:

  • df2加上1并忽略第一个值。
  • 累加结果(accumulate = TRUE

代码:

DT$df3 <- Reduce(`*`,DT$df2[-1]+1,init = 100,accumulate = TRUE)
DT
#    df1 df2     df3
# 1:   1   8     100
# 2:   2   9    1000
# 3:   3  10   11000
# 4:   4  11  132000
# 5:   5  12 1716000

这个方法适用于基础 R,如果想要使用更符合语言习惯的 data.table 语法,可以按照 @jogo 的建议编写:

DT[, df3:=Reduce('*', df2[-1]+1, init = 100,accumulate = TRUE)]

为了完整起见,这是使用tidyverse的方式:

library(tidyverse)
DT %>% mutate(df3 = accumulate(df2[-1]+1,`*`,.init = 100))

5

以下是 C++ 方法:

library(data.table)
library(Rcpp)
cppFunction(
  'NumericVector fun(const NumericVector x, const double y) {
     const double n = x.size();

     NumericVector res = NumericVector(n);
     res[0] = y;
     for (double i = 1; i < n; i++) {
       res[i] = res[i-1] * (x[i] + 1);
     }
     return res;
   }')

DT <- fread("   df1 df2
  1   8
  2   9
  3  10
  4  11
  5  12")

DT[, df3 := fun(df2, 100)]
# > DT
#    df1 df2     df3
# 1:   1   8     100
# 2:   2   9    1000
# 3:   3  10   11000
# 4:   4  11  132000
# 5:   5  12 1716000

注释:我仍在学习C++,这个函数基于Roland编写的另一个C++函数


1
这些简单的例子很有用,rcpp 可能很少被使用,因为它几乎从未在 SO 的基准竞赛中出现,而在那里它可能经常获胜。我从未花时间去研究它... - moodymudskipper
一个有趣的方法!非常感谢您的时间。 - Maylo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接