代码之家  ›  专栏  ›  技术社区  ›  Jordan

purrr映射未生成整齐的数据

  •  2
  • Jordan  · 技术社区  · 8 年前

    多亏了这个网站,我使用的是R purrr 打包为基于多列的聚合数据。聚合按我所希望的方式工作,但输出却不工作。以下是使用 mtcars 数据集。

    library(dplyr)
    library(purrr)
    #pull in data
    data <- mtcars
    #get colnames
    variable1 <- colnames(data)
    #map the variables
    t1 <- map(variable1, ~ data %>%
             group_by_at(.x) %>%
             summarize(number = mean(mpg))) %>%
        set_names(variable1) %>%
        bind_rows(., .id = 'variable')
    

    如果我期望有三列(预测变量、每个变量内的级别、聚合),那么我有8列。请参见下图:

    Output of above code

    如何将代码放在最上面并生成一个整洁的数据集?

    2 回复  |  直到 8 年前
        1
  •  3
  •   alistaire    8 年前

    一种简单的方法是将数据重塑为长格式,这样可以使用普通dplyr进行聚合:

    library(tidyverse)
    
    mpg_means <- mtcars %>% 
        gather(variable, value, -mpg) %>% 
        group_by(variable, value) %>% 
        summarise(mean_mpg = mean(mpg))
    
    mpg_means
    #> # A tibble: 146 x 3
    #> # Groups:   variable [?]
    #>    variable value mean_mpg
    #>    <chr>    <dbl>    <dbl>
    #>  1 am          0.     17.1
    #>  2 am          1.     24.4
    #>  3 carb        1.     25.3
    #>  4 carb        2.     22.4
    #>  5 carb        3.     16.3
    #>  6 carb        4.     15.8
    #>  7 carb        6.     19.7
    #>  8 carb        8.     15.0
    #>  9 cyl         4.     26.7
    #> 10 cyl         6.     19.7
    #> # ... with 136 more rows
    

    请注意 mtcars 完全是数字,如果您有不同的类型,转换为长格式将强制变量类型。计算结果将是相同的,但可能会在以后引起问题。要解决此问题,请使用可以处理不同类型的输出格式,例如。

    mpg_means_in_list_cols <- mtcars %>% 
        as_tibble() %>%    # compact printing for list columns
        summarise_all(list) %>%    # collapse each column into a list of itself
        gather(group, group_values, -mpg) %>% 
        mutate(mpg_means = map2(mpg, group_values,    # for each mpg/value pair, ...
                                ~tibble(mpg = .x, group_value = .y) %>%    # ...reconstruct a data frame...
                                    group_by(group_value) %>% 
                                    summarise(mean_mpg = mean(mpg))))    # ...and aggregate
    
    mpg_means_in_list_cols
    #> # A tibble: 10 x 4
    #>    mpg        group group_values mpg_means        
    #>    <list>     <chr> <list>       <list>           
    #>  1 <dbl [32]> cyl   <dbl [32]>   <tibble [3 × 2]> 
    #>  2 <dbl [32]> disp  <dbl [32]>   <tibble [27 × 2]>
    #>  3 <dbl [32]> hp    <dbl [32]>   <tibble [22 × 2]>
    #>  4 <dbl [32]> drat  <dbl [32]>   <tibble [22 × 2]>
    #>  5 <dbl [32]> wt    <dbl [32]>   <tibble [29 × 2]>
    #>  6 <dbl [32]> qsec  <dbl [32]>   <tibble [30 × 2]>
    #>  7 <dbl [32]> vs    <dbl [32]>   <tibble [2 × 2]> 
    #>  8 <dbl [32]> am    <dbl [32]>   <tibble [2 × 2]> 
    #>  9 <dbl [32]> gear  <dbl [32]>   <tibble [3 × 2]> 
    #> 10 <dbl [32]> carb  <dbl [32]>   <tibble [6 × 2]>
    

    虽然这显然没有那么漂亮,但它能够整齐地容纳许多类型。要提取上述结果,只需添加 %>% unnest(mpg_means) . 按原样,分组变量分别保存在 group_values 并在每个 mpg_means tibble。

        2
  •  2
  •   Mikko Marttila    8 年前

    将数据分组到 map ,可以将分组变量重命名为 "level" ,因为这些值将形成包含最终数据集中分组变量级别的列。

    当您有混合类型的分组变量(例如数字和字符)时,还需要将分组变量强制为字符,以便能够将结果绑定在一起。

    有了这些补充,你应该得到你所期望的。(您也可以跳过 bind_rows 通过使用 map_df 而不是 地图 ,以节省一点代码,就像我在下面所做的那样。)

    reprex::reprex_info()
    #> Created by the reprex package v0.1.1.9000 on 2018-02-09
    
    library(purrr)
    library(dplyr)
    
    data <- iris
    vars <- names(data)
    
    set_names(vars) %>% 
      map_df(function(var) {
        var <- set_names(var, "level")
        data %>% 
          group_by_at(var) %>% 
          summarize_at("Sepal.Length", "mean") %>% 
          mutate_at("level", as.character)
      }, .id = "variable")
    #> # A tibble: 126 x 3
    #>        variable level Sepal.Length
    #>           <chr> <chr>        <dbl>
    #>  1 Sepal.Length   4.3          4.3
    #>  2 Sepal.Length   4.4          4.4
    #>  3 Sepal.Length   4.5          4.5
    #>  4 Sepal.Length   4.6          4.6
    #>  5 Sepal.Length   4.7          4.7
    #>  6 Sepal.Length   4.8          4.8
    #>  7 Sepal.Length   4.9          4.9
    #>  8 Sepal.Length     5          5.0
    #>  9 Sepal.Length   5.1          5.1
    #> 10 Sepal.Length   5.2          5.2
    #> # ... with 116 more rows
    

    您还可以将流程包装在一个函数中,并允许多个变量使用多个函数进行总结。不过,你得花点时间想出一个让人想起的名字(我作弊了,只是用了 foo 此处)。

    foo <- function(data, vars, funs) {
      grps <- names(data)
      set_names(grps) %>% 
        map_df(function(grp) {
          grp <- set_names(grp, "level")
          data %>% 
            group_by_at(grp) %>% 
            summarize_at(vars, funs) %>% 
            mutate_at("level", as.character)
        }, .id = "variable")
    }
    
    foo(iris, vars(Sepal.Length, Sepal.Width), funs(mean, sd))
    #> # A tibble: 126 x 6
    #>        variable level Sepal.Length_mean Sepal.Width_mean Sepal.Length_sd
    #>           <chr> <chr>             <dbl>            <dbl>           <dbl>
    #>  1 Sepal.Length   4.3               4.3         3.000000             NaN
    #>  2 Sepal.Length   4.4               4.4         3.033333               0
    #>  3 Sepal.Length   4.5               4.5         2.300000             NaN
    #>  4 Sepal.Length   4.6               4.6         3.325000               0
    #>  5 Sepal.Length   4.7               4.7         3.200000               0
    #>  6 Sepal.Length   4.8               4.8         3.180000               0
    #>  7 Sepal.Length   4.9               4.9         2.950000               0
    #>  8 Sepal.Length     5               5.0         3.120000               0
    #>  9 Sepal.Length   5.1               5.1         3.477778               0
    #> 10 Sepal.Length   5.2               5.2         3.425000               0
    #> # ... with 116 more rows, and 1 more variables: Sepal.Width_sd <dbl>