dplyr的相对频率/比例

时间:2014-07-04 14:31:15

标签: r group-by dplyr frequency

假设我想计算每组中不同值的比例。例如,使用mtcars数据,如何通过 am (自动/手动)计算齿轮相对频率与dplyr一起去?

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

10 个答案:

答案 0 :(得分:222)

试试这个:

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'(只需在结果数据上用groups进行检查),然后我们在其上执行mutate计算。

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

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

答案 1 :(得分:33)

您可以使用dplyr功能,但根据am的版本具有不同的行为:

  • dplyr 0.7.1:返回未分组表:您需要再次按ungroup()

  • 分组
  • dplyr&lt; 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))

dplyr&lt; 0.7.1

ungroup()

这会产生分组表,如果您想将其用于进一步分析,则可以使用#!/usr/bin/perl #!perl -w use DBI; use strict; use WWW::Mechanize; my $mech= WWW::Mechanize->new(); my $url= 'https://www.splithistory.com/zsl/'; $mech -> get($url); my $script = $mech -> content; open (MYFILE, '>sd.txt'); #open file in write mode print MYFILE $script; #copy source code of website in file close(MYFILE); 删除分组属性。

答案 2 :(得分:24)

@ 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%

编辑因为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%

答案 3 :(得分:5)

这是在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
}

答案 4 :(得分:2)

我为此重复任务编写了一个小函数:

count_pct <- function(df) {
  return(
    df %>%
      tally %>% 
      mutate(n_pct = 100*n/sum(n))
  )
}

然后我可以像这样使用它

mtcars %>% 
  group_by(cyl) %>% 
  count_pct

它返回:

# A tibble: 3 x 3
    cyl     n n_pct
  <dbl> <int> <dbl>
1     4    11  34.4
2     6     7  21.9
3     8    14  43.8

答案 5 :(得分:1)

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

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

然后我将答案乘以100以得到百分比而不是小数,以使freq列更容易以百分比形式读取。

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

答案 6 :(得分:1)

尽管答案很多,但还有一种方法将prop.tabledplyrdata.table结合使用。

library("dplyr")
mtcars %>%
    group_by(am, gear) %>%
    summarise(n = n()) %>%
    mutate(freq = prop.table(n))

library("data.table")
cars_dt <- as.data.table(mtcars)
cars_dt[, .(n = .N), keyby = .(am, gear)][, freq := prop.table(n) , by = "am"]

答案 7 :(得分:0)

这是使用aggregateave的基本R答案:

df1 <- with(mtcars, aggregate(list(n = mpg), list(am = am, gear = gear), length))
df1$prop <- with(df1, n/ave(n, am, FUN = sum))
#Also with prop.table
#df1$prop <- with(df1, ave(n, am, FUN = prop.table))
df1

#  am gear  n      prop
#1  0    3 15 0.7894737
#2  0    4  4 0.2105263
#3  1    4  8 0.6153846
#4  1    5  5 0.3846154 

我们也可以使用prop.table,但是输出显示方式不同。

prop.table(table(mtcars$am, mtcars$gear), 1)
   
#            3         4         5
#  0 0.7894737 0.2105263 0.0000000
#  1 0.0000000 0.6153846 0.3846154

答案 8 :(得分:0)

出于完整性考虑,自dplyr版本1.0.0起,参数 .groups 控制{{之后的summarise函数的分组结构1}} summarise help

使用group_by.groups = "drop_last"删除最后一个分组级别。这是在1.0.0版之前获得的唯一结果。

summarise

使用library(dplyr) library(scales) original <- mtcars %>% group_by (am, gear) %>% summarise (n=n()) %>% mutate(rel.freq = scales::percent(n/sum(n), accuracy = 0.1)) #> `summarise()` regrouping output by 'am' (override with `.groups` argument) original #> # A tibble: 4 x 4 #> # Groups: am [2] #> am gear n rel.freq #> <dbl> <dbl> <int> <chr> #> 1 0 3 15 78.9% #> 2 0 4 4 21.1% #> 3 1 4 8 61.5% #> 4 1 5 5 38.5% new_drop_last <- mtcars %>% group_by (am, gear) %>% summarise (n=n(), .groups = "drop_last") %>% mutate(rel.freq = scales::percent(n/sum(n), accuracy = 0.1)) dplyr::all_equal(original, new_drop_last) #> [1] TRUE ,将删除所有级别的分组。结果变成一个独立的小标题,没有以前的.groups = "drop"

的痕迹
group_by

如果# .groups = "drop" new_drop <- mtcars %>% group_by (am, gear) %>% summarise (n=n(), .groups = "drop") %>% mutate(rel.freq = scales::percent(n/sum(n), accuracy = 0.1)) new_drop #> # A tibble: 4 x 4 #> am gear n rel.freq #> <dbl> <dbl> <int> <chr> #> 1 0 3 15 46.9% #> 2 0 4 4 12.5% #> 3 1 4 8 25.0% #> 4 1 5 5 15.6% ,则与.data相同的分组结构(在这种情况下为mtcars)。 .groups = "keep"不会剥离summarise中使用的任何变量。

最后,对于group_by,每一行都是它自己的组。在这种情况下相当于“保持”

.groups = "rowwise"

另一个有趣的问题是,有时在应用# .groups = "keep" new_keep <- mtcars %>% group_by (am, gear) %>% summarise (n=n(), .groups = "keep") %>% mutate(rel.freq = scales::percent(n/sum(n), accuracy = 0.1)) new_keep #> # A tibble: 4 x 4 #> # Groups: am, gear [4] #> am gear n rel.freq #> <dbl> <dbl> <int> <chr> #> 1 0 3 15 100.0% #> 2 0 4 4 100.0% #> 3 1 4 8 100.0% #> 4 1 5 5 100.0% # .groups = "rowwise" new_rowwise <- mtcars %>% group_by (am, gear) %>% summarise (n=n(), .groups = "rowwise") %>% mutate(rel.freq = scales::percent(n/sum(n), accuracy = 0.1)) dplyr::all_equal(new_keep, new_rowwise) #> [1] TRUE group_by之后,摘要行会有所帮助。

summarise

reprex package(v0.3.0)于2020-11-09创建

希望您发现此答案有用。

答案 9 :(得分:0)

另外,尝试add_count()(绕过讨厌的 group_by .groups)

`mtcars %>% 
  count(am, gear) %>% 
  add_count(am, wt = n) %>% 
  mutate(pct = n / nn)`