【问题标题】:dplyr: Subtracting values group-wise by group that matches given condition - unequal group sizedplyr:按组减去与给定条件匹配的值 - 不相等的组大小
【发布时间】:2020-06-25 11:17:25
【问题描述】:

我有一个类似的数据框:

UE1 <- c(rep("A", 6), rep("B", 4))
UE2 <- c(rep("T1", 3), rep("T2", 3), rep("T1", 4))
UE3 <- c(rep(c("ctrl", "X", "Y"), 2), "ctrl", "X", "Y", "Z")
value <- c(10, 20, 30, 20, 40, 60, 100, 200, 300, 400)

unequal_gp <- tibble(UE1, UE2, UE3, value)

> unequal_gp
# A tibble: 10 x 4
   UE1   UE2   UE3   value
   <chr> <chr> <chr> <dbl>
 1 A     T1    ctrl     10
 2 A     T1    X        20
 3 A     T1    Y        30
 4 A     T2    ctrl     20
 5 A     T2    X        40
 6 A     T2    Y        60
 7 B     T1    ctrl    100
 8 B     T1    X       200
 9 B     T1    Y       300
10 B     T1    Z       400

我想生成一个新列 delta_v,其中包含 value 的值,减去 UE3 中的控件 (ctrl) 的值,数据按 UE1 和 UE2 分组 - 这是我的预期结果:

# A tibble: 10 x 4
   UE1   UE2   UE3   value   delta_v
   <chr> <chr> <chr> <dbl>   <dbl>
 1 A     T1    ctrl     10   0
 2 A     T1    X        20   10
 3 A     T1    Y        30   20
 4 A     T2    ctrl     20   0
 5 A     T2    X        40   20
 6 A     T2    Y        60   40
 7 B     T1    ctrl    100   0
 8 B     T1    X       200   100
 9 B     T1    Y       300   200
10 B     T1    Z       400   300

This 答案接近我想要的,并且适用于具有相同组大小的类似数据帧(但仅当我按 E3 分组时,我不明白......?):

E1 <- c(rep("A", 6), rep("B", 6))
E2 <- c(rep("T1", 3), rep("T2", 3), rep("T1", 3), rep("T2", 3))
E3 <- c(rep(c("ctrl", "X", "Y"), 4))
value <- c(10, 20, 30, 20, 40, 60, 40, 70, 100, 100, 200, 300)

equal_gp <- tibble(E1, E2, E3, value)

equal_gp %>%
  group_by(E3) %>% #only works if i group by E3...?
  mutate(delta_v = value - filter(., E3 == "ctrl") %>% pull(value))

给予:

   E1    E2    E3    value delta_v
   <chr> <chr> <chr> <dbl>   <dbl>
 1 A     T1    ctrl     10       0
 2 A     T1    X        20      10
 3 A     T1    Y        30      20
 4 A     T2    ctrl     20       0
 5 A     T2    X        40      20
 6 A     T2    Y        60      40
 7 B     T1    ctrl     40       0
 8 B     T1    X        70      30
 9 B     T1    Y       100      60
10 B     T2    ctrl    100       0
11 B     T2    X       200     100
12 B     T2    Y       300     200

但是当我使用不相等的组大小遵循相同的逻辑时

unequal_gp %>%
  group_by(UE3) %>% 
  mutate(delta_v = value - filter(., UE3 == "ctrl") %>% pull(value))

mutate() 失败,我收到此错误:

Error: Problem with `mutate()` input `delta_v`.
x Input `delta_v` can't be recycled to size 3.
i Input `delta_v` is `value - filter(., UE3 == "ctrl") %>% pull(value)`.
i Input `delta_v` must be size 3 or 1, not 3.
i The error occured in group 4: UE3 = "Z".

从错误看来,不等组大小是问题所在,但我不知道如何解决它。任何建议都非常受欢迎 - 最好坚持 tidyverse。

谢谢

【问题讨论】:

    标签: r dplyr tidyverse


    【解决方案1】:

    你可以使用:

    library(dplyr)
    
    unequal_gp %>% 
       group_by(UE1, UE2) %>% 
       mutate(delta_v = value - value[UE3 == 'ctrl'])
    
    #   UE1   UE2   UE3   value delta_v
    #   <chr> <chr> <chr> <dbl>   <dbl>
    # 1 A     T1    ctrl     10       0
    # 2 A     T1    X        20      10
    # 3 A     T1    Y        30      20
    # 4 A     T2    ctrl     20       0
    # 5 A     T2    X        40      20
    # 6 A     T2    Y        60      40
    # 7 B     T1    ctrl    100       0
    # 8 B     T1    X       200     100
    # 9 B     T1    Y       300     200
    #10 B     T1    Z       400     300
    

    如果您在每个组的EU3 中只有一个'ctrl' 值,则上述方法将完美运行,如果您有多个值,则可以使用match 选择第一个值。

    unequal_gp %>%
      group_by(UE1, UE2) %>%
      mutate(delta_v = value - value[match('ctrl', UE3)])
    

    data.table 中的相同逻辑:

    library(data.table)
    setDT(unequal_gp)[, delta_v := value - value[match('ctrl', UE3)], .(UE1, UE2)]
    

    【讨论】:

    • 我只是想发布 exact 相同的答案... :D
    • 嗯,我们都去过那里,不是吗? ;-)
    • 我也是@MartinGal!不过,没有人能将 Ronak 击败 dplyr 答案(也许 akrun 除外 - 有时!)
    • 上帝无处不在吗?也许吧,但罗纳克肯定是:D
    猜你喜欢
    • 2018-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多