Относительные частоты/пропорции с dplyr
Предположим, что я хочу рассчитать долю разных значений в каждой группе. Например, используя данные 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
Ответы
Ответ 1
Попробуйте это:
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 виньетки:
Когда вы группируете по нескольким переменным, каждая сводка снимает один уровень группировки. Это позволяет легко свернуть набор данных.
Таким образом, после summarise
последняя из группирующих переменных 'gear' снимается, и затем данные группируются 'только' по 'am' (просто проверьте это с помощью groups
в полученных данных), по которому Затем мы выполняем расчет mutate
.
Результат отслаивания, конечно, зависит от порядка группирования переменных в вызове group_by
. Вы можете сделать следующий group_by(am)
, чтобы сделать ваш код более явным.
Для округления и предварительного уточнения, пожалуйста, обратитесь к хорошему ответу @Tyler Rinker.
Ответ 2
Вы можете использовать функцию 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))
Это приводит к сгруппированной таблице, если вы хотите использовать ее для дальнейшего анализа, может быть полезно удалить сгруппированный атрибут с помощью ungroup()
.
Ответ 3
@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%
Ответ 4
Вот общая функция, реализующая решение Хенрика на dplyr
0.7.1.
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
}
Ответ 5
Я написал небольшую функцию для этой повторяющейся задачи:
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
Ответ 6
Этот ответ основан на ответе Матифу.
Сначала я изменил его, чтобы убедиться, что я не получаю столбец freq, возвращенный в качестве столбца научной нотации, используя параметр scipen.
Затем я умножаю ответ на 100, чтобы получить процент, а не десятичный, чтобы упростить чтение столбца freq в процентах.
getOption("scipen")
options("scipen"=10)
mtcars %>%
count(am, gear) %>%
mutate(freq = (n / sum(n)) * 100)
Ответ 7
Несмотря на множество ответов, еще один подход, который использует 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"]