【问题标题】:Using `map` to find rowMeans by column names使用`map`按列名查找rowMeans
【发布时间】:2021-02-20 17:11:36
【问题描述】:

我有一个包含一致命名列的数据集,我想按组取列的平均值,例如,

library(dplyr)
library(purrr)
library(glue)

df <- tibble(`1_x_blind` = 1:3, 
       `1_y_blind` = 7:9,
       `2_x_blind` = 4:6, 
       `2_y_blind` = 5:7)
  
df %>% 
  mutate(`1_overall_test` = rowMeans(select(., matches(glue("^1_.*_blind$")))))
#> # A tibble: 3 x 5
#>   `1_x_blind` `1_y_blind` `2_x_blind` `2_y_blind` `1_overall_test`
#>         <int>       <int>       <int>       <int>            <dbl>
#> 1           1           7           4           5                4
#> 2           2           8           5           6                5
#> 3           3           9           6           7                6

这个方法很好用。对我来说,下一步是对其进行缩放,以便我可以完成整个系列的列,例如

df %>% 
  mutate(overall_blind = map(1:2, ~rowMeans(select(., matches(glue("^{.x}_.*_blind$"))))))
#> Error: Problem with `mutate()` input `overall_blind`.
#> x no applicable method for 'select' applied to an object of class "c('integer', 'numeric')"
#> ℹ Input `overall_blind` is `map(1:2, ~rowMeans(select(., matches(glue("^{.x}_.*_blind$")))))`.

我认为这里的问题是 select 混淆了 . 运算符。是否可以通过这种方式在一系列列名上map?理想情况下,我希望列名遵循上面示例中的{.x}_overall 模式。

【问题讨论】:

  • 您是否希望您的输出只有 1 个额外的 overall_blind 列表列来存储所有子组的行均值,或者您希望有很多列,例如 1_overall_test2_overall_test 等。 ?
  • 多列会更好
  • 每组的列数是固定的(总是2,即1_x,1_y),还是每组不同?
  • 数字永远是固定的

标签: r dplyr purrr


【解决方案1】:

更新这是一种不需要renamebind_cols 的更简洁的方法:

map_dfc(1:2, 
        function(x) df %>% 
          select(matches(glue("^{x}_.*_blind$"))) %>%
          mutate("{x}_overall_blind" := rowMeans(.))
        )

# A tibble: 3 x 6
  `1_x_blind` `1_y_blind` `1_overall_blind` `2_x_blind` `2_y_blind` `2_overall_blind`
        <int>       <int>             <dbl>       <int>       <int>             <dbl>
1           1           7                 4           4           5               4.5
2           2           8                 5           5           6               5.5
3           3           9                 6           6           7               6.5

上一页
这是map 方法。
挑战是基于现有列的不同组来改变两个新列。最简单的方法是在自己的 map_dfc() 中执行此操作,然后将其绑定到现有的 df


df %>%
  bind_cols(
    map_dfc(1:2, ~rowMeans(df %>% select(matches(glue("^{.x}_.*_blind$"))))) %>%
      rename_with(~paste0(str_replace(., "\\...", ""), "_overall_blind"))
  )

# A tibble: 3 x 6
  `1_x_blind` `1_y_blind` `2_x_blind` `2_y_blind` `1_overall_blind` `2_overall_blind`
        <int>       <int>       <int>       <int>             <dbl>             <dbl>
1           1           7           4           5                 4               4.5
2           2           8           5           6                 5               5.5
3           3           9           6           7                 6               6.5

这是一种使用数据透视获取行列组平均值的方法,它避免了正则表达式和mutate/map 操作:

df %>%
  mutate(row = row_number()) %>%
  pivot_longer(-row) %>%
  separate(name, c("grp"), sep = "_", extra = "drop") %>%
  group_by(row, grp) %>%
  summarise(overall_blind = mean(value)) %>%
  ungroup() %>%
  pivot_wider(id_cols = row, names_from = grp, values_from = overall_blind, 
              names_glue = "{grp}_{.value}") %>%
  bind_cols(df)

# A tibble: 3 x 6
  `1_overall_blind` `2_overall_blind` `1_x_blind` `1_y_blind` `2_x_blind` `2_y_blind`
              <dbl>             <dbl>       <int>       <int>       <int>       <int>
1                 4               4.5           1           7           4           5
2                 5               5.5           2           8           5           6
3                 6               6.5           3           9           6           7

【讨论】:

    【解决方案2】:

    这是一种解决方案:

    map_dfc(1:2, function(x) {
      select(df, matches(glue("^{x}_.*_blind$"))) %>%
        mutate(overall_blind = rowMeans(select(., matches(glue("^{x}_.*_blind$"))))) %>%
        
        # General but not perfect names
        # set_names(paste0(x, "_", names(.)))
        
        # Hand-tailored names
        set_names(c(names(.)[1], names(.)[2], paste0(x, "_", names(.)[3])))
      })
    
    #> # A tibble: 3 x 6
    #>   `1_x_blind` `1_y_blind` `1_overall_blind` `2_x_blind` `2_y_blind` `2_overall_blind`
    #>         <int>       <int>             <dbl>       <int>       <int>             <dbl>
    #> 1           1           7                 4           4           5               4.5
    #> 2           2           8                 5           5           6               5.5
    #> 3           3           9                 6           6           7               6.5
    

    我为每个组添加了两种命名 overall_blind 列的可能性,一种是更通用但不完美的名称(它与数据列的 1_2_ 重复),另一种给出您的名称想要但需要提前知道每组的列数。

    【讨论】:

      【解决方案3】:

      我们可以使用split.default根据列名模式将数据拆分为list的数据集,然后得到rowMeans并与原始数据绑定

      library(dplyr)
      library(purrr)
      library(stringr)
      df %>%
            split.default(readr::parse_number(names(.))) %>%
            map_dfc(rowMeans) %>% 
            set_names(str_c(names(.), "_overall_blind")) %>%
            bind_cols(df, .)
      # A tibble: 3 x 6
      #  `1_x_blind` `1_y_blind` `2_x_blind` `2_y_blind` `1_overall_blind` `2_overall_blind`
      #        <int>       <int>       <int>       <int>             <dbl>             <dbl>
      #1           1           7           4           5                 4               4.5
      #2           2           8           5           6                 5               5.5
      #3           3           9           6           7                 6               6.5
      

      【讨论】:

        猜你喜欢
        • 2012-12-02
        • 2016-12-08
        • 1970-01-01
        • 1970-01-01
        • 2012-11-08
        • 1970-01-01
        • 2020-09-25
        • 2010-09-22
        • 2016-01-28
        相关资源
        最近更新 更多