R

Sr. Python, muchas gracias por su candidatura; ya le llamaremos cuando... tenga modelos mixtos

Era casi todavía el siglo XX cuando yo, desesperado por hacer cosas que consideraba normales y que SAS no me permitía, pregunté a un profesor por algo como C pero para estadística. Y el profesor me contó que conocía a alguien que conocía a alguien que conocía a alguien que usaba una cosa nueva que se llamaba R y que podía servirme.

Fue amor a primera vista, pero esa es otra historia. La relevante aquí es que volví a hablar con aquel profesor para agradecerle el consejo y, de paso, le pregunté que por qué no lo usaba él. Me contestó que porque en R no había modelos mixtos (aunque nlme es anterior, del 99; ¡a saber en qué estado se encontraba entonces!).

Demasiados colores (para el hijo de un daltónico)

R

Mi padre me enseñó muchas cosas (leer, sumar, etc.). Pero mi infancia fue monocromática porque era daltónico. Siempre dibujé con lápiz (primero) y tinta (después). Las témperas y los rotuladores fueron mi tormento.

R tiene colores. Un montón. Y paletas de colores. Demasiadas. Una búsqueda entre los paquetes disponibles actualmente en CRAN de color proporciona 88 coincidencias, a las que deben sumarse las 35 adicionales de colour. Algunos de esos paquetes se refieren a asuntos tales como “Optimal Block Designs for Two-Colour cDNA Microarray Experiments”, pero los más ofrecen cosas tales como:

¿Hay demasiados paquetes en R?

R

Por su importancia, traigo aquí y resumo una serie de argumentos que he encontrado en otra parte acerca del ecosistema de paquetes en R. Que son:

  • Muchos paquetes no tienen el soporte adecuado a medio plazo.
  • Además, hay demasiados.
  • Pero su calidad es desigual.
  • Y muchos reinventan la rueda (lo manifiesta la escasa interdependencia entre los paquetes).
  • Finalmente, no es para nada sencillo identificar el paquete que puede ser útil para un fin determinado.

Cada cual elige los problemas que quiere tener (y R decidió tener los de un bazar y no los de una catedral).

Evaluación de trucos para multiplicaciones aproximadas

En Street Fighting Mathematics (leedlo) hay un capítulo en el que se discuten trucos para realizar mental y aproximadamente operaciones del tipo 3600 × 4.4 × 10^4 × 32.

La recomendación es la siguiente: contar ceros primero, gestionar las cifras significativas después. En el caso anterior, el autor identifica 8 ceros (tres del 3600, cuatro del 10^4 y uno del 32), quedando como cifras significativas 3.6, 4.4 y 3.2.

Para estas últimas, recomienda aproximarlas a 1, pocos (alrededor de 3) y 10. Pocos es una cifra que vale tres y cuyo cuadrado es 10. Por lo tanto, 3.6 × 4.4 × 3.2 es el cubo de pocos, es decir, treinta. De manera que la aproximación de 3600 × 4.4 × 10^4 × 32 es un tres seguido de nueve ceros (en realidad, es un cinco seguido de nueve ceros).

El discreto encanto de las animaciones

Representando datos, una animación es un gráfico en el que unas facetas (en terminología de ggplot2) ocultan el resto, como en

extraído de aquí y que representa la evolución del tamaño (superficie) de los coches habituales a lo largo del último siglo. Lo mismo pero evitando el indeseado efecto:

El código:

library(ggplot2)

datos <- structure(list(year = c(1930L,
  1950L, 1960L, 1970L,
  1980L, 1990L, 2000L, 2010L, 2018L),
  width = c(1.45, 1.59, 1.54, 1.56, 1.64,
           1.67, 1.75, 1.76, 1.78),
  length = c(3.38, 4.02, 3.96, 3.89, 3.98,
           4, 4.18, 4.12, 4.23)),
  class = "data.frame", row.names = c(NA, -9L))

ggplot(datos, aes(xmin = 0, ymin = 0,
  xmax = length, ymax = width)) +
  geom_rect() +
  coord_fixed() +
  facet_wrap(~ year) +
  xlab("longitud (m)") +
  ylab("anchura (m)") +
  ggtitle("Evolución de la superficie\ndel coche 'promedio'")

data.tree: porque no todos los datos son tabulares

R

De acuerdo, casi todos los datos son tabulares. Digamos que el 90% de ellos. Pero muchos de ellos, no. Y data.tree es un paquete con muy buena pinta para manejar estructuras arborescentes de datos: véanse esta y esta viñeta.

Como no podía ser de otra manera, tiene funciones para recorrer, filtrar y podar los árboles de datos.

La aplicación gracias a la cual di con él es el paquete prof.tree, que es lo mismo que el Rprof de toda la vida… solo que mola más:

Siete años después, dejo la presidencia de la Comunidad R Hispano

R

Eso, que dejo la comunidad de la Comunidad R Hispano. Ocho años después, que ya son. La noticia, en todo caso, no es tanto que abandone la presidencia sino las circunstancias que me condujeron a ella. Noticias viejas, pero noticias al fin y al cabo, que sirven para entender por qué lo fui entonces y por qué dejo de serlo ahora.

La Comunidad R Hispano (por qué se llama así y no, como habría sido natural, Asociación Española de Usuarios de R, es una larga historia que tal vez cuente algún día) se fundó en Madrid hace ocho años en el seno de las III Jornadas de Usuarios de R (a todo esto, esa página la hice yo en html puro y con vi como editor), cuando la comunidad (informal) de usuarios de R ya llevaba un tiempo desarrollando actividades.

Colinealidad y posterioris

En esta entrada voy a crear un conjunto de datos donde dos variables tienen una correlación muy alta, ajustar un modelo de regresión y obtener la siguiente representación de la distribución a posteriori de los coeficientes,

donde se aprecia el efecto de la correlación entre x1 y x2.

El código,

library(mvtnorm)
library(rstan)
library(psych)

n <- 100
corr_coef <- .9

x <- rmvnorm(n, c(0, 0),
  sigma = matrix(c(1, corr_coef, corr_coef, 1), 2, 2))
plot(x)

x1 <- x[,1]
x2 <- x[,2]
x3 <- runif(n) - 0.5

y <- 1 + .4 * x1 - .2 * x2 + .1 * x3 + rnorm(n, 0, .1)

summary(lm(y ~ x1 + x2 + x3))

stan_code <- "
data {
  int N;
  vector[N] y;
  vector[N] x1;
  vector[N] x2;
  vector[N] x3;
}
parameters {
  real a;
  real a1;
  real a2;
  real a3;
  real sigma;
}

model {
  a ~ cauchy(0,10);
  a1 ~ cauchy(0,2.5);
  a2 ~ cauchy(0,2.5);
  a3 ~ cauchy(0,2.5);

  y ~ normal(a + a1 * x1 + a2 * x2 + a3 * x3, sigma);
}"


datos_stan <- list(
    N = n,
    y = y,
    x1 = x1,
    x2 = x2,
    x3 = x3
)

fit2 <- stan(model_code = stan_code,
              data = datos_stan,
              iter = 10000, warmup = 2000,
              chains = 2, thin = 4)

res <- as.data.frame(fit2)
pairs.panels(res[, c("a", "a1", "a2", "a3", "sigma")])

¿Siguen votando igual los diputados?

Hace seis años escribí esto. Hoy actualizo aquella entrada para crear

Y, por supuesto, el código (que he tenido que reescribir en gran medida):

library(xml2)
library(reshape2)
library(plyr)

# descarga y manipulación de datos

dia_votacion <- function(n.votacion){
  dir.create("tmp")
  url <- paste("https://app.congreso.es/votacionesWeb/OpenData?sesion=",
                n.votacion, "&completa;=1&legislatura;=12", sep = "")
  download.file( url, destfile = "./tmp/votos.zip")
  try(unzip("./tmp/votos.zip", exdir = "./tmp"), TRUE)

  ficheros <- dir("./tmp", pattern = ".*xml", full.names = T)

  if (length(ficheros) == 0)
    return(NULL)

  res <- lapply(ficheros, function(fichero){

    print(fichero)

    datos <- as_list(read_xml(fichero))

    sesion <- datos$Resultado$Informacion$Sesion
    numero <- datos$Resultado$Informacion$NumeroVotacion

    try(datos <- ldply(datos$Resultado$Votaciones, unlist), TRUE)

    if (class(datos) == "try-error")
      return(NULL)

    if (class(datos) != "data.frame")
      return(NULL)

    if(nrow(datos) == 0)
      return(NULL)

    datos$sesion <- sesion
    datos$numero <- numero

    datos
  })

  unlink("./tmp", recursive = T)      # borra el directorio temporal

  res
}

tmp <- lapply(1:156, dia_votacion)

datos <- tmp[!sapply(tmp, is.null)]
datos <- lapply(datos, function(x) do.call(rbind, x))
datos <- do.call(rbind, datos)

datos$numero <- as.numeric(unlist(datos$numero))
datos$sesion <- as.numeric(unlist(datos$sesion))

datos$asunto <- as.character(1000000 + 1000 * datos$sesion + datos$numero)

datos$ind <- 0
datos$ind[datos$Voto == "No"] <- -1
datos$ind[datos$Voto == "Sí"] <- 1

tmp <- dcast(datos, asunto ~ Diputado, value.var = "ind", fill = 0)
matriz_votos <- as.matrix(tmp[, -1])

rownames(matriz_votos) <- NULL
colnames(matriz_votos) <- NULL

heatmap(matriz_votos, xlab = "Diputados", ylab = "Asuntos", scale = "none")

No sé si alguien querrá sacarle más punta a la no historia de hoy.

Cuatro paquetes interesantes de R

R

Son paquetes que marcado como potencialmente relevantes pero que aún no he revisado como debiera. Tal vez alguien tenga algo más que decir sobre ellos. Tiene los comentarios, por supuesto, abiertos.

longRPart2: Particionamiento recursivo para modelos longitudinales. Extiende ctree y, por supuesto, mob del paquete party a datos de tipo longitudinal.

radiant: Más que un paquete, es un conjunto de paquetes para business analytics usando R y Shiny. Ni idea de para qué parte de ese amplio campo del business analytics puede resultar útil, pero si resulta que es precisamente el tuyo, ¡enhorabuena!