假设我想计算每组中不同值的比例。例如,使用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
答案 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
当您按多个变量分组时,每个摘要都会剥离一个分组级别。这样可以轻松逐步汇总数据集。
因此,在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.table
与dplyr
或data.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)
这是使用aggregate
和ave
的基本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)`