【问题标题】:Conditionally mutate new columns based on pattern根据模式有条件地改变新列
【发布时间】:2021-02-17 18:15:35
【问题描述】:

我想改变(在本例中为变形)新列,以添加包含特定模式的所有列。新列也应称为模式。我想避免将数据转换为长格式并避免引用附加到模式的字符串。

在下面的例子中,'b\\d+' 是模式:

 df <- tribble(
  ~a1_b1, ~a1_b2, ~a1_b3, ~a2_b1, ~a2_b2, ~a2_b3, ~a3_b1, ~a3_b2, ~a3_b3, ~a4_b1, ~a4_b2, ~a4_b3,
  1,      2,      3,      4,      5,      6,      7,      8,      9,      10,     11,     12
)

预期输出:

df %>%
  transmute(b1 = a1_b1 + a2_b1 + a3_b1 + a4_b1,
         b2 = a1_b2 + a2_b2 + a3_b2 + a4_b2,
         b3 = a1_b3 + a2_b3 + a3_b3 + a4_b3)
# A tibble: 1 x 3
     b1    b2    b3
  <dbl> <dbl> <dbl>
1    22    26    30

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    不使用pivot_longer

    library(stringr)
    library(dplyr)
    df %>% 
      transmute(across(starts_with('a1'),
          ~ . + get(str_replace(cur_column(), '.*_', 'a2_')))) %>%
      rename_all(~ str_remove(., '.*_'))
    

    -输出

    # A tibble: 1 x 3
    #     b1    b2    b3
    #  <dbl> <dbl> <dbl>
    #1     5     7     9
    

    split.default

    library(purrr)
    df %>% 
      split.default(str_remove(names(.), '_.*')) %>% 
      reduce(`+`) %>%
      rename_all(~ str_remove(., '.*_')) 
    #   b1 b2 b3
    #1  5  7  9
    

    或者使用更新的数据集

    df %>% 
       split.default(str_remove(names(.), '_.*')) %>% 
       reduce(`+`) %>%
       rename_all(~ str_remove(., '.*_')) 
    #  b1 b2 b3
    #1 22 26 30
    

    或使用map

    library(purrr)
    names(df) %>%
      str_remove('.*_') %>% 
      unique %>% 
      map_dfc(~ df %>% 
               select(ends_with(.x)) %>%
               transmute(!! .x := rowSums(.)))
    # A tibble: 1 x 3
    #     b1    b2    b3
    #  <dbl> <dbl> <dbl>
    #1    22    26    30
    

    这是pivot_longer的选项

    library(tidyr)
    library(tibble)
    df %>% 
       pivot_longer(cols = everything(), names_to = c(".value", 'group'),
          names_sep = "_") %>% 
      transmute(group, new = a1 + a2) %>%
      deframe %>% 
      as_tibble_row
    

    或者另一种方式是

    df %>% 
       pivot_longer(cols = everything(), 
        names_to = c( 'group', '.value'), names_sep = "_") %>%
       summarise(across(c(b1:b3), sum))
    # A tibble: 1 x 3
    #     b1    b2    b3
    #  <dbl> <dbl> <dbl>
    #1    22    26    30
    

    【讨论】:

    • 感谢您的回答,抱歉,我刚刚编辑了“我想避免旋转”
    • 确实如此,你能概括最后一个答案吗?如果我不想专门调用 a1 和 a2
    • @Ali 你能举个更一般的例子吗?不清楚
    • @Ali 我展示了 4 个解决方案。如果它们都不适合你,那好吧。
    • @Ali split.default方法有问题吗
    猜你喜欢
    • 2012-12-09
    • 2023-01-08
    • 2018-11-04
    • 1970-01-01
    • 2022-11-19
    • 2020-10-19
    • 2021-10-15
    • 2020-03-16
    • 1970-01-01
    相关资源
    最近更新 更多