Dplyr parece que prefiere los factores

Con datos bajados de aquí:

library(MicroDatosEs)
library(dplyr)
library(microbenchmark)
library(ggplot2)

censo <- censo2010("MicrodatosCP_NV_per_nacional_3VAR.txt")

censo_char <- as.data.frame(censo[, c("CPRO", "SEXO", "ECIVIL", "FACTOR")])
censo_factor <- censo_char
censo_factor$CPRO <- factor(censo_factor$CPRO)


foo <- function(x)
    x %>% group_by(CPRO) %>% summarise(res = sum((SEXO == "Mujer") * (ECIVIL == "Divorciado") * FACTOR) / sum(FACTOR) * 100)

res <- microbenchmark(
    char = foo(censo_char),
    factor = foo(censo_factor),
    times = 10
)

autoplot(res)

Da:

¿No es sorprendente? De hecho, plyr es más rápido que dplyr en este caso si no se usan factores.

Notas:

  • El hilo de por qué es así en lugar de otra manera se pierde en código escrito en C++. Para otra vida (mía o de otro).
  • Debo agradecer a Diego Castro el intercambio de ideas, código y perplejidades que dieron pie a todo lo de arriba.

5 comentarios sobre “Dplyr parece que prefiere los factores

  1. Iñaki 5 agosto, 2019 11:59

    Es fácil ver por qué sucede esto examinando la variable de agrupación tras una operación agrupada: está ordenada. Y es mucho más rápido ordenar integers que ordenar strings.

    ¿Por qué ordenan? ¿Es esto bueno o malo? Encontrarás largas discusiones al respecto si las buscas.

  2. Carlos J. Gil Bellosta 5 agosto, 2019 20:08

    Vaya, no esperaba que fuesen por ahí los tiros. Y, efectivamente, R tarda mucho, mucho más en ordenar enteros que cadenas. Es algo que no esperaba. Sobre todo cuando los «vectores de cadenas» en R son «punteros a cadenas» y los niveles repetidos se almacenan una única vez (es decir, los vectores de strings son prácticamente lo mismo que los factores internamente).

    Una cosa me queda clara («usar factores con datos grandes»); y otra no: si lo anterior es «bug» o «feature».

  3. José Luis Cañadas 6 agosto, 2019 12:09

    Mi pequeño Leni (lenovo de hace unos años) no ha podido con el censo, pero lo que dice Iñaki tiene sentido. No sabía que los vectores de strings eran prácticamente como los factores, siempre he pensado que tener factores era mejor que cadenas para cosas como las que cuentas.

  4. Iñaki 6 agosto, 2019 15:54

    Siempre es mejor tener factores que cadenas. El hecho de que R almacene las cadenas de forma única y tenga punteros a ellas es un tema de eficiencia de memoria, pero supone poca o nula diferencia a la hora de ordenar.

    Ordenar implica comparar, y comparar un entero es una operación, mientras que las cadenas son complejas de comparar en general; particularmente, si tienen diferente codificación. Es por eso que R por defecto emplea radix para todo menos para cadenas, de forma que diferentes codificaciones sean interpretables y comparables. Si sabemos positivamente que tenemos una codificación homogénea, podemos forzar radix en cadenas. Y aun con todo, la comparación byte a byte de cadenas será en general más lenta que la de enteros, a no ser que todos los niveles se diferencien en el primer byte.

Comenta

Your email address will not be published.

Puedes usar estas etiquetas y atributos de HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.