R

Regresión tradicional vs multinivel

Ayer se leía en Twitter que

Cabe preguntarse qué pasa si se analizan los mismos datos usando ambas técnicas. Obviamente, hay muchos tipos de datos y supongo que los resultados variarán según qué variante se utilice. Aquí voy a centrarme en unos donde hay medidas repetidas de un factor aleatorio. También voy a situarme en un contexto académico, en el que interesan más las estimaciones de los efectos fijos, que en uno más próximo a mi mundo, la consultoría, donde son más relevantes las estimaciones regularizadas de los efectos aleatorios.

Spike and slab: otro método para seleccionar variables

Me sorprende ver todavía a gente utilizar técnicas stepwise para la selección de variables en modelos. Sobre todo, existiendo herramientas como elastic net o lasso.

Otra de las técnicas disponibles es la del spike and slab (de la que oí hablar, recuerdo, por primera vez en el artículo de Varian Big Data: New Tricks for Econometrics). Es una técnica de inspiración bayesiana en cuya versión más cruda se imponen sobre las variables del modelo de regresión prioris que son una mezcla de dos distribuciones:

Consumo alimentario mensual en los hogares españoles en R

R

[Coge aire: aquí arranca una frase muy larga] Simplemente, que he creado un repositorio en GitHub para extraer información de los ficheros excel y sus muchas pestañas que componen el sistema de difusión de datos estadísticos sobre consumo de alimentos y bebidas de las familias que realiza el ministerio de como se llame ahora.

La página de ministerio es esta; el repositorio, este.

Nota: hay mucha información muy buena que merece ser más conocida y mejor explotada.

CausalImpact me ha complacido mucho

Estoy aquí analizando datos para un cliente interesado en estudiar si como consecuencia de uno de esos impuestos modennos con los que las administraciones nos quieren hacer más sanos y robustos. En concreto, le he echado un vistazo a si el impuesto ha encarecido el precio de los productos gravados (sí) y si ha disminuido su demanda (no) usando CausalImpact y me ha complacido mucho que la salida de summary(model, "report") sea, literalmente, esta:

Densidades unidimensionales en R

R

Es un asunto tangencial que, además, se soluciona las más de las veces con density. Pero parece que tiene mucha más ciencia detrás.

Por algún motivo, acabé un día en la página del paquete logspline, que ajusta densidades usando splines. Su promesa es que puede realizar ajustes de densidades tan finos como

que está extraído de Polynomial Splines and their Tensor Products in Extended Linear Modeling, el artículo que le sirve de base teórica. El algoritmo subyacente es capaz, como da a entender el gráfico anterior, de graduar la resolución en la determinación de la densidad para representar debidamente tanto las zonas con detalles finos sin difuminarlos como las regiones más aburridas sin crear irregularidades espurias.

Casos de coronavirus en Madrid provincia: un modelo un poco menos crudo basado en la mortalidad (II)

[Nota: el código relevante sigue estando en GitHub. No es EL código sino UN código que sugiere todos los cambios que se te puedan ocurrir. Entre otras cosas, ilustra cómo de dependientes son los resultados de la formulación del modelo, cosa muchas veces obviada.]

Continúo con la entrada de ayer, que contenía más errores que información útil respecto a objetivos y métodos.

Los objetivos del análisis son los de obtener una estimación del número de casos activos de coronavirus en la provincia de Madrid. La de los casos oficiales tiene muchos sesgos por culpa de los distintos criterios seguidos para determinarlos a lo largo del tiempo. Sin embargo, es posible que los fallecimientos debidos al coronavirus, antes al menos de que se extienda el triaje de guerra, son más fiables. Eso sí, la conexión entre unos (casos) y otros (defunciones) depende de una tasa de letalidad desconocida. El objetivo del modelo es complementar la información de los casos notificados con la de defunciones.

Casos de coronavirus en Madrid provincia: un modelo muy crudo basado en la mortalidad

R

[Nota: si no sabes interpretar las hipótesis embebidas en el código que publico, que operan como enormes caveats, no hagas caso en absoluto a los resultados. He publicado esto para ver si otros que saben más que yo lo pulen y consiguen un modelo más razonable usándolo tal vez, ojalá, como núcleo.]

[Edición: He subido el código a GitHub.]

[El código de esta sección y los resultados contienen errores de bulto; consúltese el código de GitHub.]

k-vecinos + lmer

El de los k-vecinos es uno de mis métodos favoritos de modelización. Al menos, teóricamente: luego, en la práctica, es complicado construir una función de distancias decente. Pero tiene la ventaja indiscutible de ser tremendamente local: las predicciones para una observación concreta dependen únicamente de su entorno.

lme4::lmer (y sus derivados) es ya casi la lente a través de la que imagino cómo operan las variables dentro de un modelo. Desafortunadamente, es un modelo global y no gestiona particularmente bien las interacciones, cuando son muchas y complejas.

lme4 + simulate

Esta entrada es casi una referencia para mí. Cada vez tiro más de lme4 en mis modelos y en uno en concreto que tengo entre manos toca simular escenarios. Para lo cual, simulate.merMod.

Véamoslo en funcionamiento. Primero, datos (ANOVA-style) y el modelo que piden a gritos:

library(plyr)
library(lme4)

a <- c(0,0,0, -1, -1, 1, 1, -2, 2)
factors <- letters[1:length(a)]

datos <- ldply(1:100, function(i){
    data.frame(x = factors, y = a + rnorm(length(a)))
})
modelo <- lmer(y ~ (1 | x), data = datos)

El resumen del modelo está niquelado:

summary(modelo)

# Linear mixed model fit by REML ['lmerMod']
# Formula: y ~ (1 | x)
# Data: datos
#
# REML criterion at convergence: 2560.3
#
# Scaled residuals:
#     Min      1Q  Median      3Q     Max
# -3.6798 -0.6442 -0.0288  0.6446  3.3582
#
# Random effects:
#     Groups   Name        Variance Std.Dev.
# x        (Intercept) 1.5197   1.2328
# Residual             0.9582   0.9789
# Number of obs: 900, groups:  x, 9
#
# Fixed effects:
#     Estimate Std. Error t value
# (Intercept) -0.009334   0.412212  -0.023

En particular,

Interacciones y selección de modelos

Desafortunadamente, el concepto de interacción, muy habitual en modelización estadística, no ha penetrado la literatura del llamado ML. Esencialmente, el concepto de interacción recoge el hecho de que un fenómeno puede tener un efecto distinto en subpoblaciones distintas que se identifican por un nivel en una variable categórica.

El modelo lineal clásico,

$$ y \sim x_1 + x_2 + \dots$$

no tiene en cuenta las interacciones (aunque extensiones suyas, sí, por supuesto).

Seguimiento de los nuevos casos diarios de coronavirus en «tiempo real» con R

R

El código usado en

es

library(reshape2)
library(ggplot2)
library(plyr)

url <- "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Confirmed.csv"
cvirus <- read.table(url, sep = ",", header = T)

cvirus$Lat <- cvirus$Long <- NULL
cvirus$Province.State <- NULL

cvirus <- melt(cvirus, id.vars = "Country.Region")

colnames(cvirus) <- c("país", "fecha", "casos")
cvirus$fecha <- as.Date(as.character(cvirus$fecha),
    format = "X%m.%d.%y")

tmp <- cvirus[cvirus$país %in% c("Italy", "Spain",
    "France", "Germany", "South Korea", "UK"),]

foo <- function(x){
    x <- x[order(x$fecha),]
    data.frame(fecha = x$fecha[-1],
        casos = diff(x$casos))
}

res <- ddply(tmp, .(país), foo)

res$país <- reorder(res$país, res$casos, function(x) -max(x))

res <- res[res$fecha > as.Date("2020-02-15"),]

ggplot(res, aes(x = fecha, y = casos)) +
    geom_point(size = 0.5) + geom_line(alpha = 0.3) +
    facet_wrap(~país, scales = "free_y") +
    ggtitle("Coronavirus: new daily cases") +
    theme_bw()

ggsave("/tmp/new_daily_cases.png", width = 12,
    height = 8, units = "cm")

Más sobre el "método delta": propagate

Por referencia y afán de completar dos entradas que hice hace un tiempo sobre el método delta, esta y esta, dejo constar mención al paquete propagate, que contiene métodos para la propagación de la incertidumbre.

Para desavisados: si $latex x \sim N(5,1)$ e $latex y \sim N(10,1)$, ¿cómo sería la distribución de $latex x/y$? Etc.

Seguimiento del coronavirus en "tiempo real" con R

R

Mi código (guarrongo) para seguir la evolución del coronavirus por país en cuasi-tiempo real:

library(reshape2)
library(ggplot2)

url <- "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Confirmed.csv"
cvirus <- read.table(url, sep = ",", header = T)

cvirus$Lat <- cvirus$Long <- NULL
cvirus$Province.State <- NULL

cvirus <- melt(cvirus, id.vars = "Country.Region")

colnames(cvirus) <- c("país", "fecha", "casos")

cvirus <- cvirus[cvirus$país %in% c("Italy", "Spain"),]
cvirus$fecha <- as.Date(as.character(cvirus$fecha), format = "X%m.%d.%y")

ggplot(cvirus, aes(x = fecha, y = casos, col = país)) + geom_line()

tmp <- cvirus
tmp$fecha[tmp$país == "Spain"] <- tmp$fecha[tmp$país == "Spain"] - 9
ggplot(tmp, aes(x = fecha, y = casos, col = país)) + geom_line()

tmp <- tmp[tmp$fecha > as.Date("2020-02-14"),]

ggplot(tmp, aes(x = fecha, y = log10(casos), col = país)) + geom_line()

Los datos están extraídos de aquí, por si alguien quiere reemplazar casos por defunciones o recuperados.