首页 > 解决方案 > 对子组内的计算(cumsum)使用单一、通用的组特定基线

问题描述

我正在寻找一个整洁的解决方案,最好使用

这个问题与这个答案是一致的,但是它确实有一个额外的转折。我的数据有一个整体分组变量“grp”。在每个这样的中,我想根据“试验”定义的子组cumsum中的累积总和( )执行计算,这里和。XY

但是,对于两个子组(试验“X”和试验“Y”)内的计算,我需要使用单一的、共同的组特定基线,即试验所在的位置B

我想要的结果Value3在下面的数据集中desired_outcome

# library(tidyverse)
# library(dplyr)
desired_outcome # see below I got this `desired_outcome`
# A tibble: 10 x 6
# Groups:   grp [2]
   grp   trial    yr value1 value2 Value3
   <chr> <fct> <dbl>  <dbl>  <dbl>  <dbl>
 1 A     B      2021      2      0      2
 2 A     X      2022      3      1      5
 3 A     X      2023      4      2     10
 4 A     Y      2022      5      3      7
 5 A     Y      2023      6      4     16
 6 B     B      2021      0      2      0
 7 B     X      2022      1      3      3
 8 B     X      2023      2      4      8
 9 B     Y      2022      3      5      5
10 B     Y      2023      4      6     14

我的最小工作示例。数据第一,

tabl <- tribble(~grp, ~trial, ~yr, ~value1, ~value2,
                'A', "B", 2021, 2, 0,
                'A', "X", 2022, 3, 1,
                'A', "X", 2023, 4, 2,
                'A', "Y", 2022, 5, 3,
                'A', "Y", 2023, 6, 4,
                'B', "B", 2021, 0, 2,
                'B', "X", 2022, 1, 3,
                'B', "X", 2023, 2, 4,
                'B', "Y", 2022, 3, 5,
                'B', "Y", 2023, 4, 6) %>% 
 mutate(trial = factor(trial, levels = c("B", "X", "Y"))) %>% 
  arrange(grp, trial, yr) 

现在,我需要使用group_by(),但我无法分组,trial因为我需要使用基线B来计算“X”和“Y”。

undesired_outcome_tidier_code <- tabl %>% 
  group_by(grp) %>% # this do not work!
  mutate(Value1.1 = cumsum(value1),
         Value2.1 = lag(cumsum(value2), default = 0),
         Value3   = Value1.1 + Value2.1) %>% 
         select(-Value1.1, -Value2.1)

undesired_outcome_tidier_code第 4-5 行和第 9-10 行中,出于显而易见的原因,没有分别使用第 1 行和第 6 行作为基线。如图所示,

undesired_outcome_tidier_code
# A tibble: 10 x 6
# Groups:   grp [2]
   grp   trial    yr value1 value2 Value3
   <chr> <fct> <dbl>  <dbl>  <dbl>  <dbl>
 1 A     B      2021      2      0      2
 2 A     X      2022      3      1      5
 3 A     X      2023      4      2     10
 4 A     Y      2022      5      3     17
 5 A     Y      2023      6      4     26
 6 B     B      2021      0      2      0
 7 B     X      2022      1      3      3
 8 B     X      2023      2      4      8
 9 B     Y      2022      3      5     15
10 B     Y      2023      4      6     24

我正在寻找一种让我desired_outcome(见下文)整洁的解决方案。

在这个较小的示例中,我可以绕过它来获得 my desired_outcome,但这是一个繁琐的两步解决方案。必须有更好/更整洁的方式。

step1 <- tabl  %>% arrange(grp, trial, yr)  %>% filter(trial  != 'Y') %>% 
  group_by(grp) %>% 
  mutate(Value1.1 = cumsum(value1),
         Value2.1 = lag(cumsum(value2), default = 0),
         Value3   = Value1.1 + Value2.1)

step2 <- tabl  %>% arrange(grp, trial, yr)  %>% filter(trial  != 'X') %>% 
  group_by(grp) %>% 
  mutate(Value1.1 = cumsum(value1),
         Value2.1 = lag(cumsum(value2), default = 0),
         Value3   = Value1.1 + Value2.1)
    
desired_outcome <- rbind(step1, 
      step2 %>% filter(trial  != 'B') 
                         ) %>% select(-Value1.1, -Value2.1) %>% arrange(grp, trial, yr) 

标签: roptimizationtidyversecumsum

解决方案


加上purrr,您可以执行以下操作:

map(.x = c("X", "Y"),
    ~ tabl %>%
     arrange(grp, trial, yr) %>%
     filter(trial != .x) %>%
     group_by(grp) %>% 
     mutate(value3 = cumsum(value1) + lag(cumsum(value2), default = 0))) %>% 
 reduce(full_join) %>%
 arrange(grp, trial, yr) 

  grp   trial    yr value1 value2 value3
   <chr> <fct> <dbl>  <dbl>  <dbl>  <dbl>
 1 A     B      2021      2      0      2
 2 A     X      2022      3      1      5
 3 A     X      2023      4      2     10
 4 A     Y      2022      5      3      7
 5 A     Y      2023      6      4     16
 6 B     B      2021      0      2      0
 7 B     X      2022      1      3      3
 8 B     X      2023      2      4      8
 9 B     Y      2022      3      5      5
10 B     Y      2023      4      6     14

推荐阅读