Formas más rápidas de calcular frecuencias y transmitir de largo a ancho
Estoy intentando obtener recuentos de cada combinación de niveles de dos variables, "semana" e "id". Me gustaría que el resultado tuviera "id" como filas, "semana" como columnas y los recuentos como valores.
Ejemplo de lo que he probado hasta ahora (probé muchas otras cosas, incluida la adición de una variable ficticia = 1 y luego fun.aggregate = sum
sobre eso):
library(plyr)
ddply(data, .(id), dcast, id ~ week, value_var = "id",
fun.aggregate = length, fill = 0, .parallel = TRUE)
Sin embargo, debo estar haciendo algo mal porque esta función no finaliza. ¿Hay una mejor manera de hacer esto?
Aporte:
id week
1 1
1 2
1 3
1 1
2 3
Producción:
1 2 3
1 2 1 1
2 0 0 1
Podrías usar el table
comando:
table(data$id,data$week)
1 2 3
1 2 1 1
2 0 0 1
Si "id" y "semana" son las únicas columnas en su marco de datos, simplemente puede usar:
table(data)
# week
# id 1 2 3
# 1 2 1 1
# 2 0 0 1
La razón ddply
por la que se tarda tanto es que la división por grupo no se ejecuta en paralelo (solo los cálculos de las 'divisiones'), por lo tanto, con una gran cantidad de grupos será lento (y .parallel = T
) no ayudará.
Un enfoque que utilice data.table::dcast
( data.table
versión >= 1.9.2) debería ser extremadamente eficiente en tiempo y memoria. En este caso, podemos confiar en los valores de argumento predeterminados y simplemente usar:
library(data.table)
dcast(setDT(data), id ~ week)
# Using 'week' as value column. Use 'value.var' to override
# Aggregate function missing, defaulting to 'length'
# id 1 2 3
# 1: 1 2 1 1
# 2: 2 0 0 1
O establecer los argumentos explícitamente:
dcast(setDT(data), id ~ week, value.var = "week", fun = length)
# id 1 2 3
# 1: 1 2 1 1
# 2: 2 0 0 1
Para data.table
alternativas anteriores a 1.9.2, consulte las ediciones.
Una tidyverse
opción podría ser:
library(dplyr)
library(tidyr)
df %>%
count(id, week) %>%
pivot_wider(names_from = week, values_from = n, values_fill = list(n = 0))
#spread(week, n, fill = 0) #In older version of tidyr
# id `1` `2` `3`
# <dbl> <dbl> <dbl> <dbl>
#1 1 2 1 1
#2 2 0 0 1
Usando solo pivot_wider
-
tidyr::pivot_wider(df, names_from = week,
values_from = week, values_fn = length, values_fill = 0)
O usando tabyl
desde janitor
:
janitor::tabyl(df, id, week)
# id 1 2 3
# 1 2 1 1
# 2 0 0 1
datos
df <- structure(list(id = c(1L, 1L, 1L, 1L, 2L), week = c(1L, 2L, 3L,
1L, 3L)), class = "data.frame", row.names = c(NA, -5L))