R

Rápido y frugal: una digresión en la dirección inhabitual

Siempre (aténganse los puristas al contexto) recomiendo comenzar con un árbol de decisión para, sobre esa base, ensayar métodos más potentes. Sobre todo si la precisión conviene más que la interpretabilidad.

En la dirección opuesta se sitúan los árboles rápidos y frugales. Un árbol rápido y frugal es un tipo de árbol de decisión tal como

fast_frugal_tree

La restricción que satisface (a diferencia de los árboles de decisión más habituales) es que:

Dos nuevos tutoriales sobre data.table y dplyr

R

Los productos de Apple, aun admitiendo su calidad, resuelven problemas que yo hace años que no tenía. Tanto data.table como dplyr vinieron a resolver problemas a los que muchos nos enfrentábamos con sudor y lágrimas.

Ha aparecido recientemente una serie de tutoriales sobre ambos paquetes que recomiendo:

Y mis comentarios:

  • Para el 99% de mis problemas de manipulación de datos, me sobra con, además de R base, reshape2 y plyr.
  • Para datos más grandes, me decanto por data.table. En gran medida, porque es previo a dplyr.
  • No obstante, tengo la sensación de que dplyr acabará llevándose el gato al agua: tengo suficientes años como para haber presenciado sin que me las cuenten batallas anteriores: Beta vs VHS, Wordperfect vs Word, etc.

Una estupenda introducción intermedia a data.table

R

Jan Gorecki ha resumido las soluciones a las cincuenta preguntas más populares sobre el paquete data.table de R en Stack Overflow y las ha resumido en forma de tutorial aquí.

Muy recomendable. Muy recomendable también data.table.

Aunque me temo que el hadleyverse, y por razones que nada tienen que ver con la calidad de la cosa, no van a dejar de él, a medio plazo, ni las raspas.

R I/O (o rio)

R

rio es otro de esos desasosegantes paquetes de R. rio contiene esencialmente tres funciones,

  • import, que lo lee todo
  • export, que lo escribe todo y
  • convert, que transforma un fichero de un formato a otro.

Según su documentación, uno puede hacer cosas como

export(mtcars, "mtcars.csv")
export(mtcars, "mtcars.rds")
export(mtcars, "mtcars.sav")

para guardar mtcars en cualquiera de los formatos indicados por la extensión y luego

x <- import("mtcars.csv")
y <- import("mtcars.rds")
z <- import("mtcars.sav")

para importarlos sin complicaciones de separadores, encabezamientos, etc. Además, ya puestos,

GLMs con prioris (casi) a voluntad

Esto que cuento hoy puede ser muy útil: cómo mejorar los GLMs mediante la introducción de prioris (casi) a voluntad sobre los coeficientes. Usando el paquete arm de R, claro.

De momento y porque aún tengo sucios los datos sobre los que me gustaría aplicar el modelo, extraeré un ejemplo de la ayuda de la función principal del paquete, bayesglm.

Primero, preparo unos datos:

n <- 100
x1 <- rnorm (n)
x2 <- rbinom (n, 1, .5)
b0 <- 1
b1 <- 1.5
b2 <- 2
y <- rbinom (n, 1, invlogit(b0+b1*x1+b2*x2))

Comenzamos con un glm de toda la vida.

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

R es un vago

Si creo la función

foo <- function(a,b) a*a + b

y la llamo mediante

foo(1 + 1,3)

pueden ocurrir dos cosas: o bien que R precalcule 1+1 y la función ejecute 2 * 2 + 3 o bien que la función ejecute directamente (1+1)*(1+1)+3. Pero, ¿qué es lo que hace realmente? Si escribimos

f1 <- function(x){
    print("Soy f1")
    x
}

f2 <- function(x){
    print("Soy f2")
    x
}

foo(f1(2), f2(3))

obtenemos

> foo(f1(2), f2(3))
[1] "Soy f1"
[1] "Soy f2"
[1] 7

lo que significa que f1 ha sido llamada una única vez. Es decir, R resuelve sus argumentos antes de aplicar la función. Pero hay más:

6602.767 km alrededor de España para visitar todas sus capitales de provincia

R

O tal dice lo que expongo a continuación.

Paquetes necesarios:

library(rvest)
library(caRtociudad)
library(reshape2)
library(ggmap)
library(plyr)
library(TSP)

Extracción de las provincias y sus capitales (de la Wikipedia):

capitales <- read_html("https://es.wikipedia.org/wiki/Anexo:Capitales_de_provincia_de_Espa%C3%B1a_por_poblaci%C3%B3n")
capitales <- html_nodes(capitales, "table")
capitales <- html_table(capitales[[1]])$Ciudad

capitales <- capitales[!capitales %in%
  c("Las Palmas de Gran Canaria",
    "Melilla", "Ceuta", "Mérida",
    "Santa Cruz de Tenerife",
    "Santiago de Compostela",
    "Palma de Mallorca")]

Y sus coordenadas:

coordenadas <- ldply(capitales, function(x) {
    tmp <- cartociudad_geocode(x)[1,]
    res <- data.frame(ciudad = x, provincia = tmp$province, lat = tmp$latitude, lon = tmp$longitude)
    if(is.na(res$lat)){
      tmp <- geocode(paste(x, "España"))
      res$lat <- tmp$lat
      res$lon <- tmp$lon
    }
    res
  })

# Pobre Logroño: ¡Cartociudad lo ubica en Asturias!
coords.logrono <- geocode("Logroño")
coordenadas$lat[coordenadas$ciudad == "Logroño"] <- coords.logrono$lat
coordenadas$lon[coordenadas$ciudad == "Logroño"] <- coords.logrono$lon

Construcción de la matriz simétrica de distancias (¡tarda un buen rato!):

Censura a la izquierda en las universidades españolas

R

(Aviso: esta entrada podría competir dignamente en una competición de titulares engañosos. Es posible que si no sepas de qué hablo regularmente te interese más esto).

En España hay pruebas de acceso a la universidad que y en algunos sitios publican las notas de corte para acceder a determinados estudios. Las he bajado escrapeando El País así

library(rvest)
library(plyr)
library(rstan)
library(reshape2)

options(mc.cores = 2)

url <- "http://elpais.com/especiales/universidades/"

pagina     <- read_html(url, encoding = "UTF8")
urls_provs <- html_nodes(pagina, "a")
urls_provs <- html_attr(urls_provs, "href")
urls_provs <- paste0("http://elpais.com", urls_provs[grep("centro/provincia", urls_provs)])

foo <- function(url){
  tmp  <- read_html(url)
  urls <- html_nodes(tmp, "a")
  urls <- html_attr(urls, "href")
  paste0("http://elpais.com", urls[grep("^/especiales/universidades/titulacion/universidad", urls)])
}

urls_univs <- sapply(urls_provs, foo)
urls_univs <- unique(unlist(urls_univs))


foo <- function(url){
  tmp <- read_html(url)
  lugares <- html_nodes(tmp, xpath = "//*/div[@class = 'lugar']")
  data.frame(carrera = html_text(html_nodes(lugares, xpath = "//*/a[@class = 'carrera']")),
              sede = html_text(html_nodes(lugares, xpath = "//*/p[@class = 'escuela']/span/a")),
              nota = html_text(html_nodes(tmp, xpath = "//*/div[@class='nota']/p/text()")))
}

res <- ldply(urls_univs, foo)

notas <- res
notas$nota <- as.numeric(as.character(res$nota))

# limpieza de datos
notas$nota[notas$nota > 5000] <- notas$nota[notas$nota > 5000] / 1000
notas <- notas[notas$nota > 0,]

notas <- notas[order(notas$nota), ]

con el objetivo de estudiar el efecto de la universidad / sede y de la carrera en el punto de corte. Esencialmente, quiero hacer algo así como lmer(nota ~ 1 + (1 | sede) + (1 | carrera), data = notas), pero hay una complicación: como creo que mis lectores sabrán, las notas de acceso tienen un valor mínimo, el del aprobado, 5. Eso significa que, de alguna manera, están censuradas por la izquierda. El modelo resultante es algo así como

Acceso a Google Analytcs desde R

R

Google Analytics puede usarse desde su consola o bien descargando datos y procesándolos por tu cuenta. Para lo cual, desde R,

require(RGoogleAnalytics)

client.id <- "1415926535-u377en6un7lugar2de7lamancha0de1cuyo5nombre0m.apps.googleusercontent.com"
client.secret <- "CEcI5nEst6pAs6Un2SecREt6-f8nt"
token <- Auth(client.id,client.secret)
#save(token,file="~/.ga_token_file")

Obviamente, para lo anterior:

  • Hay que instalar y cargar los paquetes relevantes
  • Tienes que usar tu propio id y secreto de cliente como indica aquí
  • Tienes que tener una cuenta en Google Analytics, claro

Además, puedes descomentar la última línea si quieres guardar tus credenciales para futuros usos (con las debidas medidas de seguridad). Tras lo cual,

R sobre el EC2 de Amazon hace casi siete años: una concesión a la melancolía

Corría el año 2009 cuando comencé mi segunda aventura bloguera (nadie, yo incluido, quiere rememorar la segunda) cuando Raúl Vaquerizo tuvo la caridad de aceptarme como colaborador en Análisis y Decisión.

En diciembre de aquel año escribí cómo utilizar R en una cosa que entonces comenzaba a sonar: la nube y, en concreto, el servicio EC2 de Amazon.

El resultado, probablemente totalmente desfasado, fue este.

Material de hemeroteca, alimento de melancolías.

Detección de "outliers" locales

Aunque outlier local parezca oxímoron, es un concepto que tiene sentido.

Un outlier es un punto dentro de un conjunto de datos tan alejado del resto que diríase generado por un mecanismo distinto que el resto. Por ejemplo, puedes tener las alturas de la gente y alguna observación que parece producto de otra cosa como, por ejemplo, errores mecanográficos en la transcripción. Un outlier está lejos del resto. Pero, ¿cuánto?

Con ciertas distribuciones tiene sentido pensar que los outliers son puntos a una distancia superior a nosecuántas desviaciones típicas de la media. Más en general, fuera de un determinado círculo. Una medida similar: serían outliers aquellos puntos que a una determinada distancia solo tienen un determinado porcentaje (pequeño) del resto. Todas estas son medidas globales.