R

Estructura poblacional de España: 2010-2050

Si se puede hacer para Japón, también se puede hacer para España:

El código,

library(idbr)
library(ggplot2)
library(animation)
library(ggthemes)

idb_api_key("pídela en https://www.census.gov/data/developers/data-sets/international-database.html")

male <- idb1('SP', 2010:2050, sex = 'male')
male$SEX <- "hombres"
male$POP <- -male$POP

female <- idb1('SP', 2010:2050, sex = 'female')
female$SEX <- "mujeres"

spain <- rbind(male, female)

saveGIF({

  for (i in 2010:2050) {

    title <- as.character(i)

    year_data <- spain[spain$time == i, ]

    g1 <- ggplot(year_data, aes(x = AGE, y = POP, fill = SEX, width = 1)) +
      coord_fixed() +
      coord_flip() +
      annotate('text', x = 98, y = -300000,
                label = 'Datos: US Census Bureau IDB; idbr R package', size = 3) +
      geom_bar(data = subset(year_data, SEX == "mujeres"), stat = "identity") +
      geom_bar(data = subset(year_data, SEX == "hombres"), stat = "identity") +
      scale_y_continuous(breaks = seq(-300000, 300000, 150000),
                          labels = paste0(as.character(c(seq(300, 0, -150), c(150, 300))), "k"),
                          limits = c(min(spain$POP), max(spain$POP))) +
      theme_economist(base_size = 14) +
      scale_fill_manual(values = c('#ff9896', '#d62728')) +
      ggtitle(paste0('Estructura poblacional de España en, ', title)) +
      ylab('Población') +
      xlab('Edad') +
      theme(legend.position = "bottom", legend.title = element_blank()) +
      guides(fill = guide_legend(reverse = TRUE))

    print(g1)

  }

}, movie.name = 'spain_pyramid.gif', interval = 0.1,
    ani.width = 700, ani.height = 600)

¿Podéis probarme/le CatastRo? Porfa...

R

CatastRo es un paquete de R para explotar la API del Catastro que fue realizado por un alumno mío de la UTAD, Ángel Delgado, como proyecto de fin de máster.

Ahora, una vez integrado en rOpenSpain, toca transformarlo de un proyecto académico en un paquete útil y práctico. Vamos, exponerlo al proceloso piélago del uso para que le crujan las costuras y ver cuáles son las mejoras más pertinentes.

Así que estáis todos invitados a probar el código, verificar que la documentación documenta, que los ejemplos ejemplifican, etc. y, por supuesto, a notificar cualquier cosa que observéis abriéndole un issue al paquete, como poco.

mgm (no la de las pelis sino la de los modelos gráficos)

Cayeron en mis manos unos datos que no puedo publicar, pero me atreveré a presentar algunos resultados anonimizados. Se trata de una tabla de puntuaciones numéricas (18 en total, cada una en su columna) proporcionadas por unos cuantos centenares de sujetos (filas). Era de interés un estudio cualitativo de las posibles relaciones de dependencia entre las variables.

La manera más rápida de comenzar, un heatmap(cor(dat)), para obtener

Y luego PCA y todas esas cosas.

Mortalidad en carretera (contada de una manera distinta)

Con motivo de fin de año se ha hablado de fallecidos en accidentes de tráfico como por ejemplo en El Mundo o en El País. Y sí, parece que el número observado de muertos ha aumentado.

Lo cual es mucho menos relevante de lo que se da a entender. Si tiras una moneda al aire 100 veces y sacas 48 caras y luego repites el experimento, podrías sacar 53 (y habría aumentado el número observado de caras) o 45 (y habría disminuido). Lo relevante es si ha cambiado o no la probabilidad de cara de la moneda. De lo cual, y volviendo al caso de la siniestralidad, ya me ocupé en su día.

La distribución de Poisson y la estabilización de la varianza

Imagínate que quieres estabilizar la varianza (¡para qué!) de una distribución de Poisson. Los libros viejunos te dirán que saques la raíz cuadrada de tus valores.

Si en lugar de mirar en libros viejunos prestas atención a tus propios ojos, harás algo parecido a:

lambdas <- -10:10
lambdas <- 2^lambdas
res <- sapply(lambdas,
    function(lambda) sd(sqrt(rpois(1e5, lambda))))

para obtener

y averiguar dónde funciona y dónde no.

Si usas la transformación $latex f(x) = x^{2/3}$, como recomiendan en cierto artículo que no viene a cuento identificar, harás

Cuidado con los $

R

El otro tropezamos con el siguiente artefacto:

a <- list(aa = 12, bb = 14)
is.null(a$a)
#[1] FALSE
a$a
#[1] 12

No es un bug de R, por que la documentación reza:

x$name is equivalent to x[[“name”, exact = FALSE]]

Y se pueden constrastar:

a[["a", exact = FALSE]]
a[["a", exact = TRUE]]

Comentarios:

  • Odio muchísimo los bugs que no son bugs porque están documentados en el la nota ‡2.a.(c), párrafo §23.3 de la sección 14 de un manual oscuro.
  • Odio mucho al os gilipollas que se complacen en mandarte a leer manuales.
  • Odio mucho las violaciones del principio de mínima sorpresa.
  • Soy consciente de que R es, fundamentalmente, una plataforma de análisis interactivo y no (o solo subsidiariamente) un lenguaje de programación.
  • Soy consciente de que muchos de los defaults de R se decidieron antes de que se popularizasen los completadores de comandos.

La magnitud de la sequía

Cuando tienes una serie temporal al uso (sin entrar a definir qué es eso), uno puede aplicar descomposiciones tmabién al uso, como stl, para extraer tendencia y estacionalidad, de la forma

como en esta entrada previa.

Lluvia.

La serie de la lluvia es otra cosa. Uno ve si llueve o no llueve (típicamente no). Lo que uno no ve es la probabilidad, que varía a lo largo del año, de que llueva. Pasa lo mismo con monedas (uno ve caras o cruces, no la probabilidad de cara), clientes que compran (uno ve si compra o no, no la probabilidad de compra), etc. Pero la probabilidad existe y en estimarla consiste frecuentemente el trabajo de algunos.

dbf · xlsx · pdf

R

Me escriben pidiendo consejo sobre cómo leer datos contenidos en (una serie larga de) ficheros en formatos .dbf, .xlsx (con un formato extraño) y .pdf.

.dbf

No tengo ni curiosidad por averiguar de dónde proceden. Simplemente,

library(foreign)
res <-read.dbf("R0010.DBF")

funciona de maravilla.

.xlsx

Estos sí que sé de dónde vienen (y me guardo la opinión). El problema aquí no era leer directamente tablas contenidas en hojas sino ir extrayendo celdas y rangos de hojas. Así que:

Arqueólogos bayesianos

Se ve que hay arqueólogos bayesianos. Un problema con el que se encuentran es que tropiezan con cacharros antiguos y quieren estimar su antigüedad.

Así que prueban distintos métodos (¿químicos?), cada uno de los cuales con su precisión, y acaban recopilando una serie de estimaciones y errores. Obviamente, tienen que combinarlas de alguna manera.

El modelo más simple es

$$ M_i \sim N(\mu, \sigma_i)$$

donde $latex \mu$ es la antigüedad (desconocida) del artefacto y los $latex \sigma_i$ son las varianzas distintas de los distintos métodos de medida, que arrojan las estimaciones $latex M_i$.

"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.

Distribuciones hiperbólicas

    curve(-sqrt(x^2 + 1), -5, 5)

pinta una rama de hipérbola,

que, una vez exponenciada, i.e.,

    curve(exp(-sqrt(x^2 + 1)), -5, 5)

da

Es decir, una curva algo menos esbelta que la normal pero que bien podemos dividir por su integral para obtener la llamada distribución hiperbólica.

Tres notas sobre ella:

  • Tiene una historia curiosa. Fue considerada por Ralph Bagnold al estudiar la forma de las dunas y la sedimentación de la arena arrastrada por el viento. El logaritmo de sus curvas, se ve, tenía forma de hipérbola.
  • Lo cual os proporciona un exótico contraejemplo al argumento habitual sobre la naturaleza omniatractora de la normal.
  • La distribución hiperbólica (y sus extensiones) están disponibles en el paquete ghyp, motivado por aplicaciones financieras, como siempre. Esa gente es adicta a distribuciones con colas gruesas. Aunque para lo que les valen luego…

nls con odes

Más sobre secuencia de entradas acerca de ajustes no lineales. Con (casi) los mismos datos que entonces:

set.seed(155)

n <- 100

a <- 1
b <- -1/2
sigma <- 0.1

x <- runif(n, -1, 1)
y <- exp(a * x + b) + rnorm(n, 0, sigma)

dat <- data.frame(x, y)

Las y proceden de las x a través de una función no lineal exp(a * x + b). Que hoy supondremos desconocida. Supondremos únicamente que conocemos cierto mecanismo físico que determina la evolución de las y a partir de las x dado por una ecuación diferencial