如何将 Reduce() 应用于基于数据框列的组?
How to apply Reduce() to groups based on columns of a Data Frame?
我几天前发布了这个问题:(参考,这样你可以更好地理解我在这个问题上的要求)创建一个 "dynamic" 列,解决方案是使用减少()函数。现在,我希望基本上做同样的事情(计算平衡的变化,参考前一行),但数据框的子集基于特定列过滤。简而言之,我想做的是执行相同的计算,但只是针对组,所以我将 X 值作为 A、B 和 C 组的起始资本,余额的变化将 "reset" 到起始每个组的资本。
我知道上面的解释不是很清楚,所以这里有一个我想要实现的快速简化版本:
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
显然有一种更有效的方法可以做到这一点,但这正是我想要找到的。我解决它的方法是创建一个函数,它将数据框和我想应用计算的 class 作为输入,并输出具有该组修改值的数据框,然后使用一些apply 函数对所有组执行操作。但是在开始创建该功能之前,我宁愿问一下是否有办法用现有的功能来做到这一点。我正在考虑沿管道运算符使用 group_by() 但由于 Reduce() 不是来自 tidyverse 库,因此它不起作用。
做成group-by操作即可:
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()
的函数很好,尽管为了紧凑我将其交换为 accumulate()
这是 Reduce()
的 tidyverse 等价物,accumulate 参数为 TRUE。
data %>%
group_by(class) %>%
mutate(balance = Reduce(function(x, y) x + x * y, change, init = start_capital, accumulate = TRUE)[-1])
或在基数 R 中使用 ave()
:
ave(data$change, data$class, FUN = function(v) Reduce(function(x, y) x + x * y, v, init = start_capital, accumulate = TRUE)[-1])
我几天前发布了这个问题:
我知道上面的解释不是很清楚,所以这里有一个我想要实现的快速简化版本:
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
显然有一种更有效的方法可以做到这一点,但这正是我想要找到的。我解决它的方法是创建一个函数,它将数据框和我想应用计算的 class 作为输入,并输出具有该组修改值的数据框,然后使用一些apply 函数对所有组执行操作。但是在开始创建该功能之前,我宁愿问一下是否有办法用现有的功能来做到这一点。我正在考虑沿管道运算符使用 group_by() 但由于 Reduce() 不是来自 tidyverse 库,因此它不起作用。
做成group-by操作即可:
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()
的函数很好,尽管为了紧凑我将其交换为 accumulate()
这是 Reduce()
的 tidyverse 等价物,accumulate 参数为 TRUE。
data %>%
group_by(class) %>%
mutate(balance = Reduce(function(x, y) x + x * y, change, init = start_capital, accumulate = TRUE)[-1])
或在基数 R 中使用 ave()
:
ave(data$change, data$class, FUN = function(v) Reduce(function(x, y) x + x * y, v, init = start_capital, accumulate = TRUE)[-1])