studio - Frecuencias/proporciones relativas con dplyr
tabla de frecuencia para datos agrupados en r (6)
Supongamos que quiero calcular la proporción de diferentes valores dentro de cada grupo. Por ejemplo, usando los datos de mtcars
, ¿cómo puedo calcular la frecuencia relativa del número de marchas en am (automático / manual) de una vez con 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
Lo que me gustaría lograr:
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 es mejor para la usabilidad, ya que hará que el carácter de la columna ya no sea numérico, sino que coincide con lo que pediste ...
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 porque Spacedman lo solicitó :-)
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%
Aquí hay una función general que implementa la solución de Henrik en 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
}
Aquí hay una función para obtener los totales de las filas y los totales de las columnas de un par de variables.
freq_tibble <- function(data, var1, var2) {
var1 <- rlang::enquo(var1)
var2 <- rlang::enquo(var2)
data %>%
dplyr::count(!!var1, !!var2) %>%
tidyr::spread(!!var2, n, fill = 0) %>%
dplyr::mutate(Total := rowSums(dplyr::select(., -!!var1))) %>%
dplyr::bind_rows(dplyr::bind_cols(!!rlang::quo_name(var1) := "Total", dplyr::summarize_if(., is.numeric, sum)))
}
Esta respuesta se basa en la respuesta de Matifou.
Primero lo modifiqué para asegurarme de que no obtuviera la columna de frecuencia como una columna de notación científica utilizando la opción scipen.
Luego multiplico la respuesta por 100 para obtener un porcentaje en lugar de un decimal para que la columna de frecuencia sea más fácil de leer como un porcentaje.
getOption("scipen")
options("scipen"=10)
mtcars %>%
count(am, gear) %>%
mutate(freq = (n / sum(n)) * 100)
Prueba esto:
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
De la viñeta dplyr :
Cuando agrupa por múltiples variables, cada resumen se desprende de un nivel de la agrupación. Eso hace que sea más fácil acumular progresivamente un conjunto de datos.
Por lo tanto, después del summarise
, la variable de agrupamiento ''engranaje'' se despega, y los datos se agrupan ''solo'' por ''am'' (simplemente verifíquelo con groups
en los datos resultantes), en los que luego realizamos el cálculo mutate
.
El resultado del "peeling" depende, por supuesto, del orden de las variables de agrupamiento en la llamada group_by
. Tuvimos suerte esta vez, que se desprendió de la variable deseada. Es posible que desee hacer un group_by(am)
posterior, para que su código sea más explícito.
Para redondeo y embellecimiento, consulte la respuesta agradable de @Tyler Rinker.
Puede usar la función count()
, que tiene sin embargo un comportamiento diferente según la versión de dplyr
:
dplyr 0.7.1: devuelve una tabla desagrupada : debe volver a agrupar antes de la
am
dplyr <0.7.1: devuelve una tabla agrupada , por lo que no es necesario volver a agrupar, aunque es posible que desee
ungroup()
para manipulaciones posteriores
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))
Esto da como resultado una tabla agrupada , si desea usarla para un análisis posterior, puede ser útil eliminar el atributo agrupado con ungroup()
.