首页 文章

dplyr的相对频率/比例

提问于
浏览
97

假设我想计算每组中不同值的比例 . 例如,使用 mtcars 数据,如何使用 dplyr 一起计算 gears (自动/手动) gears 的相对频率?

library(dplyr)
data(mtcars)
mtcars <- tbl_df(mtcars)

# count frequency
mtcars %>%
  group_by(am, gear) %>%
  summarise(n = n())

# am gear  n
#  0    3 15 
#  0    4  4 
#  1    4  8  
#  1    5  5

我想要实现的目标:

am gear  n rel.freq
 0    3 15      0.7894737
 0    4  4      0.2105263
 1    4  8      0.6153846
 1    5  5      0.3846154

5 回答

  • 21

    这个答案是基于Matifou的答案 .

    首先,我修改它以确保我没有通过使用scipen选项将freq列作为科学记数法列返回 .

    然后我将答案乘以100以获得百分比而不是十进制,以使freq列更容易以百分比形式读取 .

    getOption("scipen") 
    options("scipen"=10) 
    mtcars %>%
    count(am, gear) %>% 
    mutate(freq = (n / sum(n)) * 100)
    
  • 191

    试试这个:

    mtcars %>%
      group_by(am, gear) %>%
      summarise (n = n()) %>%
      mutate(freq = n / sum(n))
    
    #   am gear  n      freq
    # 1  0    3 15 0.7894737
    # 2  0    4  4 0.2105263
    # 3  1    4  8 0.6153846
    # 4  1    5  5 0.3846154
    

    来自dplyr vignette

    当您按多个变量分组时,每个摘要都会剥离一个分组级别 . 这样可以轻松地逐步汇总数据集 .

    因此,在 summarise 之后,分组变量'gear'被剥离,然后数据被'am'分组'only'(仅在结果数据上用 groups 检查),然后我们在其上执行 mutate 计算 .

    'peeling'的结果当然取决于 group_by 调用中分组变量的顺序 . 这次我们很幸运,它剥离了所需的变量 . 您可能希望执行后续的 group_by(am) ,以使您的代码更加明确 .

    对于舍入和美化,请参考@Tyler Rinker的好答案 .

  • 3

    您可以使用 count() 函数,但该函数具有不同的行为,具体取决于 dplyr 的版本:

    • dplyr 0.7.1:返回一个未分组的表:你需要再次按 am 分组

    • dplyr <0.7.1:返回一个分组表,因此不需要再次分组,尽管您可能希望 ungroup() 用于以后的操作

    dplyr 0.7.1

    mtcars %>%
      count(am, gear) %>%
      group_by(am) %>%
      mutate(freq = n / sum(n))
    

    dplyr < 0.7.1

    mtcars %>%
      count(am, gear) %>%
      mutate(freq = n / sum(n))
    

    这导致 grouped table ,如果要将其用于进一步分析,则使用 ungroup() 删除分组属性可能很有用 .

  • 28

    @ Henrik的可用性更好,因为这将使列字符不再是数字但匹配你要求的...

    mtcars %>%
      group_by (am, gear) %>%
      summarise (n=n()) %>%
      mutate(rel.freq = paste0(round(100 * n/sum(n), 0), "%"))
    
    ##   am gear  n rel.freq
    ## 1  0    3 15      79%
    ## 2  0    4  4      21%
    ## 3  1    4  8      62%
    ## 4  1    5  5      38%
    

    EDIT 因为Spacedman要求它:-)

    as.rel_freq <- function(x, rel_freq_col = "rel.freq", ...) {
        class(x) <- c("rel_freq", class(x))
        attributes(x)[["rel_freq_col"]] <- rel_freq_col
        x
    }
    
    print.rel_freq <- function(x, ...) {
        freq_col <- attributes(x)[["rel_freq_col"]]
        x[[freq_col]] <- paste0(round(100 * x[[freq_col]], 0), "%")   
        class(x) <- class(x)[!class(x)%in% "rel_freq"]
        print(x)
    }
    
    mtcars %>%
      group_by (am, gear) %>%
      summarise (n=n()) %>%
      mutate(rel.freq = n/sum(n)) %>%
      as.rel_freq()
    
    ## Source: local data frame [4 x 4]
    ## Groups: am
    ## 
    ##   am gear  n rel.freq
    ## 1  0    3 15      79%
    ## 2  0    4  4      21%
    ## 3  1    4  8      62%
    ## 4  1    5  5      38%
    
  • 1

    这是在 dplyr 0.7.1上实现Henrik解决方案的一般功能 .

    freq_table <- function(x, 
                           group_var, 
                           prop_var) {
      group_var <- enquo(group_var)
      prop_var  <- enquo(prop_var)
      x %>% 
        group_by(!!group_var, !!prop_var) %>% 
        summarise(n = n()) %>% 
        mutate(freq = n /sum(n)) %>% 
        ungroup
    }
    

相关问题