我正在寻找一个整洁的解决方案,最好是使用潮间带
这个问题与这个答案是一致的,但它确实有一个额外的扭曲。我的数据有一个整体分组变量'grp‘。在每个这样的组中,我想在由‘X’和Y定义的子组中执行基于累积和(X)的计算。
然而,对于两个子组内的计算,试验"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上分组,因为我需要在计算"X“和"Y”时使用基线,B。
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 (见下文)在一个整洁的方式。
在这个较小的例子中,我可以绕开它,来实现我的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) 发布于 2021-03-13 13:42:46
通过添加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发布于 2021-03-13 14:40:42
你可以试试这个。
calculate_value3是一个像您描述的那样计算value3的函数。它对trial的每一封信都这样做。它总是包括对基线的观察。不管字母是否不同于X和Y。注意,baseline可以是你想要的任何字母,我现在把它设为"B“。map-reduce解决方案。map将为每个唯一的trial运行函数calculate_value3,reduce将将它们与coalesce一起设置(这将取代所有NAs ->这就是为什么我将v3初始化为calculate_value3中所有NAs的向量)。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该解决方案对于试验的标识符是灵活的,并且似乎相当容易调试和编辑,如果需要的话,至少对我来说是这样。
发布于 2021-03-14 16:44:03
由于tidyverse似乎不是一个严格的要求,所以我借此机会提出一个data.table替代方案:
从“desired_outcome”数据开始,只为了便于比较结果:
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 := )
https://stackoverflow.com/questions/66613994
复制相似问题