【问题标题】:Using mutate rowwise over a subset of columns在列的子集上使用 mutate rowwise
【发布时间】:2019-01-30 22:47:26
【问题描述】:

我正在尝试创建一个新列,该列将包含对 tibble 列的子集逐行执行的计算结果,并且将此新列添加到现有 tibble。像这样:

df <- tibble(
ID = c("one", "two", "three"),
A1 = c(1, 1, 1),
A2 = c(2, 2, 2),
A3 = c(3, 3, 3)
)

我实际上想从基础 R 中执行此代码的 dplyr 等效:

df$SumA <- rowSums(df[,grepl("^A", colnames(df))])

我的问题是这不起作用:

df %>% 
select(starts_with("A")) %>% 
mutate(SumA = rowSums(.))
    # some code here

...因为我去掉了“ID”列,以便让 mutate 在其他(数字)列上运行 rowSums。我试图在变异后在管道中 cbind 或 bind_cols ,但它不起作用。 mutate 的任何变体都不起作用,因为它们在原地工作(在 tibble 的每个单元格内,而不是跨列,即使是按行)。

这确实有效,但我认为这不是一个优雅的解决方案:

df %>% 
mutate(SumA = rowSums(.[,grepl("^A", colnames(df))]))

是否有任何基于 tidyverse 的解决方案,不需要 grepl 或方括号,而只需要更标准的 dplyr 动词和参数?

我的预期输出是这样的:

df_out <- tibble(
ID = c("one", "two", "three"),
A1 = c(1, 1, 1),
A2 = c(2, 2, 2),
A3 = c(3, 3, 3),
SumA = c(6, 6, 6)
)

最好的 千焦

【问题讨论】:

  • 哇,谢谢大家,那里有很多很棒的想法 - 很难选择首选答案。我喜欢 Callum You 的 pmap(尽管 reduce 仍然让我感到困惑 :-),我喜欢 G. Grothendieck 的嵌套管道(我不知道你能做到这一点)和 utubun 的 Callum You 解决方案的简化版本。跨度>

标签: r dplyr


【解决方案1】:

这是使用purrr::pmaptidyverse 中进行逐行计算的一种方法。这最好与实际需要逐行运行的函数一起使用;简单的加法可能会以更快的方式完成。基本上,我们使用selectpmap 提供输入列表,如果您需要正则表达式,我们可以使用select 助手,例如starts_withmatches

library(tidyverse)
df <- tibble(
  ID = c("one", "two", "three"),
  A1 = c(1, 1, 1),
  A2 = c(2, 2, 2),
  A3 = c(3, 3, 3)
)

df %>%
  mutate(
    SumA = pmap_dbl(
      .l = select(., starts_with("A")),
      .f = function(...) sum(...)
    )
  )
#> # A tibble: 3 x 5
#>   ID       A1    A2    A3  SumA
#>   <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 one       1     2     3     6
#> 2 two       1     2     3     6
#> 3 three     1     2     3     6

reprex package (v0.2.1) 于 2019 年 1 月 30 日创建

【讨论】:

    【解决方案2】:

    这是一种不同的方法,它不会按行移动,而是利用加法的矢量化特性和加法通勤。这样可以重复使用 +purrr::reduce

    library(tidyverse)
    df <- tibble(
      ID = c("one", "two", "three"),
      A1 = c(1, 1, 1),
      A2 = c(2, 2, 2),
      A3 = c(3, 3, 3)
    )
    
    df %>%
      mutate(
        SumA = reduce(
          .x = select(., starts_with("A")),
          .f = `+`
        )
      )
    #> # A tibble: 3 x 5
    #>   ID       A1    A2    A3  SumA
    #>   <chr> <dbl> <dbl> <dbl> <dbl>
    #> 1 one       1     2     3     6
    #> 2 two       1     2     3     6
    #> 3 three     1     2     3     6
    

    reprex package (v0.2.1) 于 2019 年 1 月 30 日创建

    【讨论】:

      【解决方案3】:

      1) 要做到这一点,rowSums 尝试在 mutate 中嵌套第二个管道,如下所示:

      library(dplyr)
      
      df %>% mutate(Sum = select(., starts_with("A")) %>% rowSums)
      

      给予:

      # A tibble: 3 x 5
        ID       A1    A2    A3   Sum
        <chr> <dbl> <dbl> <dbl> <dbl>
      1 one       1     2     3     6
      2 two       1     2     3     6
      3 three     1     2     3     6
      

      2) 另一种方法是将其重塑为长格式,然后进行总结:

      library(dplyr)
      library(purrr)
      library(tidyr)
      
      df %>%
        mutate(Sum = gather(., key, value, -ID) %>% 
                     group_by(., ID) %>%
                     summarize(sum = sum(value)) %>%
                     ungroup %>%
                     pull(sum))
      

      给予:

      # A tibble: 3 x 5
        ID       A1    A2    A3   Sum
        <chr> <dbl> <dbl> <dbl> <dbl>
      1 one       1     2     3     6
      2 two       1     2     3     6
      3 three     1     2     3     6
      

      【讨论】:

        【解决方案4】:

        [upd] 我没有注意到@Calum 使用了几乎相同的方法。

        另一种可能的方法:

        library(dplyr)
        library(purrr)
        
        dat %>%
          mutate(SumA = pmap_dbl(select(., contains('A')), sum))   
        

        数据:

        # dat <- tibble(
        #   ID = c("one", "two", "three"),
        #   A1 = c(1, 1, 1),
        #   A2 = c(2, 2, 2),
        #   A3 = c(3, 3, 3)
        # )
        

        输出:

        # # A tibble: 3 x 5
        #   ID       A1    A2    A3  SumA
        #   <chr> <dbl> <dbl> <dbl> <dbl>
        # 1 one       1     2     3     6
        # 2 two       1     2     3     6
        # 3 three     1     2     3     6
        

        【讨论】:

          【解决方案5】:

          您可以在嵌套列上嵌套和使用rowSums

          library(tidyverse)
          df %>% nest(-ID) %>%
            mutate(SumA = map_dbl(data,rowSums)) %>%
            unnest
          
          # # A tibble: 3 x 5
          #      ID  SumA    A1    A2    A3
          #   <chr> <dbl> <dbl> <dbl> <dbl>
          # 1   one     6     1     2     3
          # 2   two     6     1     2     3
          # 3 three     6     1     2     3
          

          或者pmap 方法的这个变体:

          df %>% mutate(SumA = pmap_dbl(.[-1],sum))
          # # A tibble: 3 x 5
          #      ID    A1    A2    A3  SumA
          #   <chr> <dbl> <dbl> <dbl> <dbl>
          # 1   one     1     2     3     6
          # 2   two     1     2     3     6
          # 3 three     1     2     3     6
          

          并且表明基础有时更容易:

          df$SumA <- rowSums(df[-1])
          

          【讨论】:

            猜你喜欢
            • 2018-02-16
            • 1970-01-01
            • 2015-05-02
            • 2016-01-10
            • 1970-01-01
            • 1970-01-01
            • 2021-04-01
            • 2021-07-24
            相关资源
            最近更新 更多