1

几天前我发布了这个问题:如何在 R 中创建“动态”列?(参考,这样你就可以更好地理解我在这个问题上的要求)创建一个“动态”列,解决方案是使用 Reduce() 函数。现在,我希望基本上做同样的事情(计算余额变化作为参考前一行),但使用基于特定列过滤的数据框子集。简而言之,我想做的是执行相同的计算,但只针对组,所以我将 X 值作为 A、B 和 C 组的起始资本,余额的变化将“重置”为起始资本每组。

我知道上面的解释不是很清楚,所以这是我想要实现的快速简化版本:

class <- c("a", "a", "b", "b", "c", "c")
profit <- c(10, 15, -5, -6, 20, 5)
change <- profit / 1000
balance <- c(1010, 1025, 1020, 1014, 1036, 1039)

data <- data.frame(class, profit, change, balance)

a <- data %>% filter(class == "a")
b <- data %>% filter(class == "b")
c <- data %>% filter(class == "c")
start_capital = 1000

a_bal <- Reduce(function(x, y) x + x*y, a$change, init = start_capital, accumulate = TRUE)[-1]
a <- mutate(a, balance = a_bal, 
               profit = balance - (balance / (1 + change)))

b_bal <- Reduce(function(x, y) x + x*y, b$change, init = start_capital, accumulate = TRUE)[-1]
b <- mutate(b, balance = b_bal, 
            profit = balance - (balance / (1 + change)))            

c_bal <- Reduce(function(x, y) x + x*y, c$change, init = start_capital, accumulate = TRUE)[-1]
c <- mutate(c, balance = c_bal, 
            profit = balance - (balance / (1 + change)))

data <- bind_rows(a, b, c)

  class profit change balance
1     a  10.00  0.010 1010.00
2     a  15.15  0.015 1025.15
3     b  -5.00 -0.005  995.00
4     b  -5.97 -0.006  989.03
5     c  20.00  0.020 1020.00
6     c   5.10  0.005 1025.10

显然有一种更有效的方法可以做到这一点,但这就是我想要找到的。我解决它的方法是创建一个函数,将数据框和我想要应用计算的类作为输入,并输出具有该组修改值的数据框,然后使用一些应用函数来执行对所有组的操作。但是在开始创建该功能之前,我想问是否有办法用现有的方法来做到这一点。我正在考虑沿管道运算符使用 group_by() ,但由于 Reduce() 不是来自 tidyverse 库,所以它不起作用。

4

1 回答 1

0

只需使其成为分组操作:

library(dplyr)
library(purrr)

data %>%
  group_by(class) %>%
  mutate(balance = accumulate(.f = ~ .x + .x * .y, change, .init = start_capital)[-1])

# A tibble: 6 x 5
# Groups:   class [3]
  class profit change balance     y
  <fct>  <dbl>  <dbl>   <dbl> <dbl>
1 a         10  0.01     1010 1010 
2 a         15  0.015    1025 1025.
3 b         -5 -0.005    1020  995 
4 b         -6 -0.006    1014  989.
5 c         20  0.02     1036 1020 
6 c          5  0.005    1039 1025.

请注意,您误解并且不仅限于将 tidyverse 函数与 tidyverse 一起使用。您可以使用任何合适的功能。您使用的功能Reduce()很好,尽管为了紧凑性,我将其换成了与累积参数为 TRUEaccumulate()的 tidyverse 等价物。Reduce()

data %>%
  group_by(class) %>%
  mutate(balance = Reduce(function(x, y) x + x * y, change, init = start_capital, accumulate = TRUE)[-1])

ave()在基础 R 中使用:

ave(data$change, data$class, FUN = function(v) Reduce(function(x, y) x + x * y, v, init = start_capital, accumulate = TRUE)[-1])
于 2020-03-08T22:59:22.293 回答