首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在子组中使用单独的、特定于组的基准(累计值)进行计算。

在子组中使用单独的、特定于组的基准(累计值)进行计算。
EN

Stack Overflow用户
提问于 2021-03-13 13:21:19
回答 3查看 110关注 0票数 4

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

这个问题与这个答案是一致的,但它确实有一个额外的扭曲。我的数据有一个整体分组变量'grp‘。在每个这样的组中,我想在由‘X’和Y定义的子组中执行基于累积和(X)的计算。

然而,对于两个子组内的计算,试验"X“和试验"Y",我需要使用一个单一的、特定于组的基线,即在试验为B的情况下。

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

代码语言:javascript
复制
# 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

我最起码的工作例子。数据第一,

代码语言:javascript
复制
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上分组,因为我需要在计算"X“和"Y”时使用基线,B

代码语言:javascript
复制
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行作为基线。如图所示,

代码语言:javascript
复制
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 (见下文)在一个整洁的方式。

在这个较小的例子中,我可以绕开它,来实现我的desired_outcome,但这是一个麻烦的两步解决方案。必须有更好/更整洁的办法。

代码语言:javascript
复制
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) 
EN

回答 3

Stack Overflow用户

发布于 2021-03-13 13:42:46

通过添加purrr,您可以执行以下操作:

代码语言:javascript
复制
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
票数 3
EN

Stack Overflow用户

发布于 2021-03-13 14:40:42

你可以试试这个。

  • calculate_value3是一个像您描述的那样计算value3的函数。它对trial的每一封信都这样做。它总是包括对基线的观察。不管字母是否不同于X和Y。注意,baseline可以是你想要的任何字母,我现在把它设为"B“。
  • 在管道中,您需要一个map-reduce解决方案。map将为每个唯一的trial运行函数calculate_value3reduce将将它们与coalesce一起设置(这将取代所有NAs ->这就是为什么我将v3初始化为calculate_value3中所有NAs的向量)。
代码语言:javascript
复制
calculate_value3 <- function(ut, # trial under examination
                             tr, # trial vector
                             v1, # value1 vector
                             v2, # value2 vector
                             baseline = "B"){ # baseline id
  
  v3      <- rep_len(NA, length(tr))
  ind     <- ut == tr | baseline == tr
  cumv1   <- cumsum(v1[ind]) 
  cumlv2  <- cumsum(lag(v2[ind], default = 0)) 
  v3[ind] <- cumv1 + cumlv2
  v3
  
}

library(purrr)
tabl %>% 
  group_by(grp) %>% 
  mutate(value3 = reduce(
    
    map(unique(trial), calculate_value3,
        tr = trial, v1 = value1, v2 = value2), 
    
    coalesce)) %>%
  ungroup()

#> # A tibble: 10 x 6
#>    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

该解决方案对于试验的标识符是灵活的,并且似乎相当容易调试和编辑,如果需要的话,至少对我来说是这样。

票数 1
EN

Stack Overflow用户

发布于 2021-03-14 16:44:03

由于tidyverse似乎不是一个严格的要求,所以我借此机会提出一个data.table替代方案:

从“desired_outcome”数据开始,只为了便于比较结果:

代码语言:javascript
复制
library(data.table)
setDT(desired_outcome)

desired_outcome[ , v3 := {
  c(value1[1], sapply(c("X", "Y"), function(g){
    .SD[trial %in% c("B", g), (cumsum(value1) + cumsum(shift(value2, fill = 0)))[-1]]
  }))}, by = grp]

#     grp trial   yr value1 value2 Value3 v3
#  1:   A     B 2021      2      0      2  2
#  2:   A     X 2022      3      1      5  5
#  3:   A     X 2023      4      2     10 10
#  4:   A     Y 2022      5      3      7  7
#  5:   A     Y 2023      6      4     16 16
#  6:   B     B 2021      0      2      0  0
#  7:   B     X 2022      1      3      3  3
#  8:   B     X 2023      2      4      8  8
#  9:   B     Y 2022      3      5      5  5
# 10:   B     Y 2023      4      6     14 14

对于每个'grp‘(by = grp),循环“试用”"X“和"Y”(sapply(c("X", "Y"))。在by (.SD)定义的每个子数据集中,选择‘试用’等于"B“或循环的当前值(trial %in% c("B", g))的行。

执行计算(cumsum(value1) + cumsum(shift(value2, fill = 0))并删除第一个值([-1]) )。在每个'grp‘中追加第一行,即对应于试用"B“(c(value1[1], ...)的行。通过引用将结果赋值给一个新变量(v3 := )

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66613994

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档