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

对分组变量进行汇总和子集设置

  •  0
  • nadizan  · 技术社区  · 7 年前

    我怎样才能做到 summarize_at ?

    数据:

    library(dplyr)
    set.seed(100)
    test_df <- data.frame(var_name=c(rep(LETTERS[1:3],each=3),"C"),
                          group_name=c(1,1,0,0,1,0,1,1,1,1),
                          obs_1=rnorm(10),
                          obs_2=rnorm(10))
    

    我想达到的目标是:

    test_df %>%
      group_by(var_name) %>%
      summarise(delta_obs1 = median(obs_1[group_name==1])-median(obs_1[group_name==0]),
                delta_obs2 = median(obs_2[group_name==1])-median(obs_2[group_name==0]),
                n_group1   = length(which(group_name==0)),
                n_group0   = length(which(group_name==1)))
    
    # A tibble: 3 x 5
      var_name delta_obs1 delta_obs2 n_group1 n_group0
        <fctr>      <dbl>      <dbl>    <int>    <int>
    1        A -0.1064135  0.2947143        1        2
    2        B -0.4857362 -0.2318824        2        1
    3        C         NA         NA        0        4
    

    然而,如果有许多列(就像我的实际情况一样),这就相当混乱和乏味。

    这个 总结 我无法使用的版本:

    fun_obs_median <-
      function(x) {
        median(x[.$group_name == 1]) - median(x[.$group_name == 0])
      }
    
    test_df %>%
      group_by(var_name) %>%
      summarize_at(.vars = colnames(.)[3:4],
                   .funs=fun_obs_median)
    

    Error in summarise_impl(.data, dots) : Evaluation error: object '.' not found.

    1 回复  |  直到 7 年前
        1
  •  1
  •   AntoniosK    7 年前

    这将有助于:

    library(tidyverse)
    
    set.seed(100)
    test_df <- data.frame(var_name=c(rep(LETTERS[1:3],each=3),"C"),
                          group_name=c(1,1,0,0,1,0,1,1,1,1),
                          obs_1=rnorm(10),
                          obs_2=rnorm(10))
    
    # function to calculate delta
    delta_f = function(x) x[2]-x[1]
    
    test_df %>%
      group_by(var_name, group_name) %>%                          # for each combination of var and group
      summarise_at(vars(matches("obs")), median) %>%              # get the median for all columns that match "obs"
      arrange(var_name, group_name) %>%                           # for each var get group == 0 in first row and group == 1 in second row
      summarise_at(vars(matches("obs")), funs(delta = delta_f))   # apply delta function
    
    # # A tibble: 3 x 3
    #   var_name obs_1_delta obs_2_delta
    #   <fct>          <dbl>       <dbl>
    # 1 A             -0.106       0.295
    # 2 B             -0.486      -0.232
    # 3 C             NA          NA 
    

    看起来像 arrange() 部分是不必要的,因为分组会自动按所需方式排列行。但是,最好保持这种状态,以防将来由于包更新而导致行为改变。

    为了计数你可以用这个

    test_df %>%
      mutate(group_name = paste0("n_group", group_name)) %>%
      count(var_name, group_name) %>%
      spread(group_name, n, fill = 0)
    
    # # A tibble: 3 x 3
    #   var_name n_group0 n_group1
    #   <fct>       <dbl>    <dbl>
    # 1 A               1        2
    # 2 B               2        1
    # 3 C               0        4
    

    然后把两张桌子连在一起 var_name .