假设我想计算每个组中不同值的比例。例如,使用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

当前回答

@Henrik's的可用性更好,因为这将使列字符,不再是数字,但符合您的要求…

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%

因为这是太空人要求的:-)

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%

其他回答

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

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

试试这个:

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的小插图:

当您按多个变量分组时,每个摘要都会剥离分组的一个层次。这使得逐步上卷数据集变得很容易。

因此,在总结之后,去掉group_by中指定的最后一个分组变量‘gear’。在突变步骤中,数据由剩余的分组变量“am”分组。您可以在每个步骤中用组检查分组。

剥离的结果当然取决于group_by调用中分组变量的顺序。您可能希望执行后续的group_by(am),以使代码更显式。

关于舍入和修饰,请参考@Tyler Rinker的精彩回答。

下面是在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
}

@Henrik's的可用性更好,因为这将使列字符,不再是数字,但符合您的要求…

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%

因为这是太空人要求的:-)

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%

尽管有很多答案,但还有一种方法使用prop。与dplyr或data.table结合使用。

library(dplyr)

mtcars %>%
  group_by(am, gear) %>% 
  tally() %>% 
  mutate(freq = prop.table(n))

#> # A tibble: 4 × 4
#> # Groups:   am [2]
#>      am  gear     n  freq
#>   <dbl> <dbl> <int> <dbl>
#> 1     0     3    15 0.789
#> 2     0     4     4 0.211
#> 3     1     4     8 0.615
#> 4     1     5     5 0.385
library(data.table)
cars_dt <- as.data.table(mtcars)
cars_dt[, .(n = .N), keyby = .(am, gear)][, freq := prop.table(n), by = "am"][]

#>    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

使用reprex v2.0.2创建于2022-10-22