Stan

Curso de estadística aplicada con Stan: ejercicio 1

A primeros de julio impartí un curso de estadística bayesiana aplicada con Stan. Tengo que examinar a los alumnos y he aquí el primero de los ejercicios:

En un país, se extrae una muestra de 2000 hombres y mujeres con la siguiente distribución:

men   <- 170 + 3 * rt(1000, 6)
women <- 160 + 2 * rt(1000, 5)
heights <- c(men, women)

Ajusta una distribución (una mezcla de dos distribuciones de Student) usando los datos anteriores, i.e., heights. Puedes suponer conocidos:

  • Los pesos de la mezcla (0.5) cada uno.
  • Que los grados de libertad de las t’s están entre 3 y 8 aproximadamente.
  • Experimenta con otros tamaños muestrales y comenta los resultados obtenidos (y los tiempos de ejecución).

Nota: este problema está motivado por una aplicación real: el ajuste de distribuciones de pérdida en banca y seguros. Típicamente, se mezclan dos distribuciones, una para la cola de la distribución y otra para el cuerpo. Hay técnicas frecuentistas (p.e., EM) para resolver estos problemas. Pero me parecen menos naturales y menos flexibles que la ruta 100% bayesiana.

Las tres culturas

Breiman habló de las dos. Dice, y tiene razón, que:

Según él, la estadística tradicional rellena la caja negra con:

¡Aburrido, aburrido, aburrido! Aburrido y limitado (aunque, hay que admitirlo, útil en ocasiones muy concretas). Breiman sugiere sustituir las cajas negras que encontramos en la naturaleza por otras cajas negras conceptuales:

Que es aún más aburrido y patrimonio, además, de toda suerte de script kiddies.

La tercera cultura reemplaza la caja negra por un modelo generativo que simula el comportamiento de la naturaleza (i.e., del sistema generador de números aleatorios pero con estructura). Y usa Stan (o sus alternativas) para estimar, predecir y, en última instancia, facilitar decisiones informadas.

Kriging con Stan

Este mes de julio, cuórum mediante, impartiré en la UPC un curso que he maltitulado, mor de brevedad, Estadística Bayesiana Aplicada.

Los cursos de estadística bayesiana son teoría, mucha teoría, y unos ejemplos tontos que quieren justificarla. Del tipo: hagamos lo que ya sabemos hacer de otra manera más; busquemos una alternativa molona al p-valor (y usémosla como usar íamos un p-valor, por supuesto), etc.

Mi curso debería haberse titulado algo así como: Problemas reales (aunque simplificados por motivos estrictamente pedagógicos) resueltos con tecnología bayesiana porque, si no, dígame Vd. cómo lo haría: ¿con optim? Jajajajaja…

Sobre el problema de las martingalas: ¿cuántos sabíais la respuesta?

Pues no se sabe bien. Además, habrá quién pudiéndola haber averiguado, prefirió dejarse llevar por la intuición y errar. Pero volvamos a los hechos. Dado

la pregunta urgente es: ¿cuántos podrían haber conocido la respuesta? Suponiendo que el conocimiento de la respuesta es algo binarizable (¿lo es?), la distribución del número de respuestas correctas sería $latex pN + X$, donde $latex N$ es el número total de respuestas, $latex p$ es la proporción de quienes sabe la respuesta y $latex X \sim B(N - pN, 1/3)$, suponiendo siempre que $latex pN$ es entero.

"Intervalos" de confianza con forma de rosquilla

Envalentonado por el comentario de Iñaki Úcar a mi entrada del otro día, que me remitía a este artículo, decidí rizar el rizo y crear intervalos de confianza no ya discontinuos sino con otra propiedad topológica imposible: homeomorfos con un toro.

Y aquí está:

El modelo, el código y demás,

library(rstan)
library(ggplot2)

n <- 100

a1 <- 1
a2 <- 1
sigma <- 0.4

datos <- data.frame(x1 = rnorm(n, 2, 0.1),
                    x2 = rnorm(n, 2, 0.1))

datos$y <- a1^datos$x1 + a2^datos$x2 + rnorm(n, 0, sigma)

codigo <- "
data {
  int<lower=1> N;
  real y[N];
  real x1[N];
  real x2[N];
}

parameters {
  real<lower=-3, upper="3"> a1;
  real<lower=-3, upper="3"> a2;
  real<lower=0, upper="3"> sigma;
}

model {
  for (n in 1:N)
    y[n] ~ normal(fabs(a1)^x1[n] +
      fabs(a2)^x2[n], sigma);
}"

fit <- stan(model_code = codigo,
    data = list(N = length(datos$y), y = datos$y,
                x1 = datos$x1, x2 = datos$x2),
    iter=40000, warmup=2000,
    chains=1, thin=10)

res <- as.data.frame(fit)

ggplot(res, aes(x = a1, y = a2)) + geom_point(alpha = 0.1)

De nuevo, no son intervalos propiamente dichos, lo convengo. Pero son configuraciones más fieles al espíritu de lo que un intervalo de confianza es y representa que su(s) letra(s) I N T E R V A L O.

Va de si hay una o dos lambdas

R

Un año, el 2016, mueren 1160 personas en accidentes de tráfico. El anterior, 1131, i.e., 29 menos. Ruido estadístico aparte, ¿aumentan?

Comenzamos a optar. Primera elección subjetiva: son muestras de una Poisson de parámetro desconocido. La pregunta: ¿el mismo?

Una manera de estudiar lo anterior es plantear

1160 ~ poisson(lambda * (1 + incr))
1131 ~ poisson(lambda)

y estudiar la distribución de incr. Que a saber qué distribución tendrá (teóricamente). Pero, ¿importa?

Mejor que rebuscar a ver qué distribución podría tener la cosa, basta con envolverlo en un poco de seudo-C++,

Vivimos en un mundo opaco e interconectado

Vivimos en un mundo opaco: como en los cuentecillos de Asimov, somos usuarios de tecnologías que ni conocemos ni controlamos. Parametrizamos nuestras máquinas y las echamos a correr. Poco más podemos hacer que fiarnos de quienes nos las proporcionan.

Luego pasan cosas como que, de repente, resulta que Stan, en las últimas versiones, ha estado produciendo muestras sesgadas. ¿Qué resultados condicionará eso río abajo?

Un caso mucho más famoso es el de la resonancia magnética (fMRI): un error en el software concomitante pone bajo sospecha hasta 40000 artículos sobre estudios del cerebro. Precisamente, por lo mismo.

Lo que pasa cuando omites la priori con variables categóricas

R

Stan. Modelo multinivel. Variable categórica. Codificación con ceros y unos. Matriz. Coeficiente vector[n_ccaa] Cccaa. Sin priori.

Catástrofe:

(Coeficientes hasta 15000. Sin tasa, con tiempo. Los valores desorbitados, en ceros de la dummy).

Priori.

for (i in 1:n_ccaa)
    Cccaa[i] ~ cauchy(0, 20);

¿Por qué no?

Tachán:

(¿Para qué verbos?)

Hamilton, Carnot y el Bosco

Por culpa de una nevera que no enfriaba como era debido, veinte años después, estoy repasando mi termodinámica: entropía, ciclo de Carnot, etc.

ciclo_carnot

Por culpa de Stan estoy repasando mi mecánica hamiltoniana.

hamiltonian_montecarlo

Y lo estoy disfrutando muchísimo.

Dizque hay una exposición del Bosco en El Prado. Que si cuesta 16 euros. Que si solo puedes ver los cuadros de lejos porque hay toneladas de gente del extrarradio que hace su visita anual al centro. Pero, sobre todo, que es goce estético para los que no pueden apreciar otra cosa. Paso. Déjeseme hacer en paz lo que me gusta.

Gestión de la mendacidad encuestoelectoral: los números

Continuando con la entrada anterior, ahora, números.

Primero, el planteamiento (cuatro partidos, etc.):

probs <- c(4, 3, 2, 1)
probs <- probs / sum(probs)
partidos <- letters[1:length(probs)]

Nos hará falta más adelante

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

Sigo con el proceso de muestreo. Reitero: cada encuestador enseña al encuestado una tarjeta al azar donde aparece el nombre de dos partidos y le pregunta si ha votado (o piensa votar) a alguno de ellos.

n <- 3000
resultados <- data.frame(
  tarjeta = sample(1:nrow(tarjetas), n, replace = T),
  partido = sample(partidos, n, prob = probs, replace = T))
resultados <- data.frame(
  tarjetas[resultados$tarjeta,],
  partido = resultados$partido)
resultados$coincide <- resultados$partido == resultados$partido1 |
  resultados$partido == resultados$partido2

# proporciones reales en la muestra
props.muestra <- table(resultados$partido) / nrow(resultados)

# resultados agregados (por tarjeta)
resultados.agg <- ddply(
    resultados, .(partido1, partido2),
    summarize,
    total = length(partido1),
    coincidencias = sum(coincide))

Y