Demasiadas conexiones a MySQL desde R

Estoy desarrollando una nueva aplicación en R+Shiny. Entre otras cosas, el servidor Shiny necesita acceder a los datos de una BBDD en MySQL. Tengo código en R que accede a MySQL sin problemas, abre y cierra las conexiones bien, sin leaks  por dejar conexiones abiertas. Bueno, eso es lo que creía… cuando por alguna razón la aplicación fallaba, podían darse casos en los que alguna conexión se quedaba abierta. Por una o dos, no pasaba «nada». Pero probando y probando, llegué a este error:

«cannot allocate a new connection — maximum of 16 connections  already opened»

Vaya… el primer problema es: ¿cómo desconecto las conexiones abiertas? La respuesta a esto en la lista de distribución de R:

 cons <- dbListConnections(MySQL()) 
 for(con in cons) 
  dbDisconnect(con)

Y ahora, ¿cómo evitar el error? Lo ideal sería establecer una especie de conexión singleton que se reutilizara desde todo el código. La respuesta a esto, en StackOverflow (cómo no ;-))

library(RMySQL)
getConnection <- function(group) {
  if (!exists('.connection', where=.GlobalEnv)) {
    .connection <<- dbConnect(MySQL(), group=group)
  } else if (class(try(dbGetQuery(.connection, "SELECT 1"))) == "try-error") {
    dbDisconnect(.connection)
    .connection <<- dbConnect(MySQL(), group=group)
  }
  return(.connection)
}

Este código comprueba si existe una conexión en el entorno global. Si no existe, la crea y la devuelve.
Si existe, comprueba que se pueda usar. Si no se puede usar, desconecta y vuelve a crear la conexión, para devolverla.
Es decir, funciona como una caché (o puede verse también como un objeto singleton de tipo connection).
Podríamos ignorar el parámetro group de la función getConnection y en su lugar, usar:

 dbConnect(MySQL(), user=login, password=pass, db=database, host=host)

allí donde fuera necesario.

Forma tu propia nube de palabras (wordcloud) con R

Una receta rápida para que no se me traspapele 🙂 El siguiente script en R lee un fichero de texto (/tmp/article.txt), lo analiza y genera una vistosa nube de palabras. Depende de los paquetes tm (text mining), RColorBrewer (para la gestión de paletas de color) y wordcloud (el verdadero artífice de la nube final). En la imagen que acompaña a este artículo se muestra la nube de palabras correspondiente al Plan vasco de Ciencia, Tecnología e Innovación 2015 (PCTi2015). Esa imagen es el resultado de ejecutar el código R objeto de este post (se genera en /tmp/cloud.png).
Quedaría ver cómo añadir el código que falta para deshacerse de los adverbios, preposiciones y demás hierbas mayores de 4 letras…

require(tm)
require(wordcloud)
require(RColorBrewer)
 
 
r <- paste(readLines(file.path("/tmp","article.txt")), collapse=' ')
r <- gsub("[ft.,;:`'\"\(\)<>]+", " ", r)
words <- tolower(strsplit(r, " +")[[1]])
 
words <- table(words)
# remove words with _bad_ chars (non utf-8 stuff)
words=words[nchar(names(words), "c")==nchar(names(words), "b")]
# remove words shorter then 4 chars
words=words[nchar(names(words), "c")>3]
# remove words accuring less than 5 times
words=words[words>4]
 
# create the image
png("/tmp/cloud.png", width=580, height=580)
pal2 <- brewer.pal(8,"Set2")
wordcloud(names(words), words, scale=c(9,.1),min.freq=3,
           max.words=Inf, random.order=F, rot.per=.3, colors=pal2)
dev.off()

Receta: Integrar R y MySQL

Vamos a por una receta rápida que permite ejecutar desde el entorno R sentencias SQL contra una BD MySQL remota (así te ahorras tener que ejecutar las sentencias en MySQL, exportar el resultado e importarlo luego en R)

Primero, asumo que la BD es remota y no hay acceso directo (el puerto 3306 está filtrado) PERO sí tenemos acceso vía SSH. Así que construyo un túnel SSH contra MySQL (en un extremo del túnel tenemos localhost, escuchando en el puerto 3307. En el otro extremo, MySQL en su servidor, escuchando en el puerto habitual, 3306)

$ ssh -L 3307:localhost:3306  usuario@IP_SERVIDOR

Ok, ahora vamos a instalar la magia: el paquete r-cran-rmysql permite lanzar sentencias SQL contra una BD MySQL remota. Y lo tenemos paquetizado en Ubuntu 🙂

$ sudo apt-get install r-cran-rmysql

Para que las conexiones a MySQL desde R no requieran que tengamos que acordarnos continuamente del login, pass, db, etc. las apuntamos en my.cnf

$ sudo vi /etc/mysql/my.cnf
[nombreGrupo]
user            = usuario
password        = password
host            = 127.0.0.1
port            = 3307
database        = nombre_de_bbdd

¡Listo! Que empiece la fiesta:

$ R
> library(RMySQL)
Loading required package: DBI
> con <- dbConnect(MySQL(), group="nombreGrupo")
> dbListTables(con)

La primera línea carga el entorno R. La segunda carga la biblioteca RMySQL. La tercera lista las tablas de la BD.

¿Más ejemplos?

> rs <- dbSendQuery(con, "select * from tabla");
> dbHasCompleted(rs)
> data <- fetch(rs, n=50);
> data[1,]

La primera línea lanza una consulta SQL. La segunda recoge los resultados (50 tuplas para empezar). La tercera muestra la primera fila de esos resultados. Para recoger TODOS los resultados/tuplas, podríamos haber hecho:

> data <- fetch(rs, n=-1);

Las consultas también pueden lanzarse y visualizarse directamente así:

> dbGetQuery(con, "show tables");

Finalmente, si no quieres crear un fichero /etc/mysql/my.cnf, también puedes pasar los datos directamente desde la línea de comandos:

> library(RMySQL)
> drv <- dbDriver("MySQL")
> con <- dbConnect(drv, user="usuario", password="contraseña", dbname="nombreDB", host="127.0.0.1", port=3307)

Para más detalles, RTFM 😉

Bonus: R insiste en mostrar los resultados sólo a 80 columnas. Si tienes una pantalla grande, igual te interesa saber que a R se le puede indicar que hay espacio de sobra 🙂 así :

> options(width=150)

El monstRuo de las galletas estadísticas

El profesor, con una caja de galletas en la mano, entra en una clase de 15 o más estudiantes y saca del bolsillo una baraja de cartas inglesa, nueva, envuelta en su plástico original sin abrir. El profesor pide a un estudiante voluntario que abra el envoltorio para pasar a quitar los comodines y barajar las cartas varias veces, delante de los alumnos. A continuación, los estudiantes son requeridos para ponerse en fila.

Van a jugar a un juego. Los estudiantes, por turnos, tomarán una carta de la parte superior de la baraja. Si la carta es negra, el afortunado habrá ganado una galleta. Si la carta es roja, el desafortunado estudiante se sentará en su sitio con las manos vacías. ¡Que empiece el juego!

El primer estudiante saca una carta: roja. Se oyen burlas y mofas, y el estudiante vuelve a su puesto. Está decepcionado, por supuesto, pero no demasiado. Después de todo se la jugaba al 50% y no ha ocurrido. Bueno, no pasa nada.

El segundo estudiante saca otra carta: roja otra vez. Se vuelven a oír mofas y burlas, y el segundo alumno se sienta en su sitio. También está decepcionado, pero de nuevo, no mucho, porque es probablemente su día de mala suerte. Vayamos con el siguiente.

El estudiante saca… ¡roja otra vez! Hay algunos listillos que levantan la voz indignados (para armar barullo, más que nada) pero hay otros que no se han molestado – están pensando. Es la tercera carta roja consecutiva, lo cual es posible, por supuesto, pero ¿qué es lo que está pasando aquí? No están seguros. Se concentran en la siguiente carta… saldrá negra, ¿no?

El cuarto saca su carta: roja. Hmmm. . . ahora hay quejas y refunfuños en lugar de mofas. Algunos del final de la fila se encogen de hombros y comienzan a sentarse en sus puestos, quejándose de que el profesor no quiere darles ni una galleta. Aunque aún quedan estudiantes en la fila, de pie, salivando, esperando a que salga la inevitable primera carta negra.

El quinto candidato saca una carta: roja. Ahora la cosa ya no tiene gracia. Mientras el resto de los estudiantes que quedaban se sientan en su puestos, la protesta continúa, y la clase entera demanda sus galletas.

Así comienza uno de los capítulos del lbro «Introduction to Probability and Statistics using R«, del profesor G. Jay Kerns. ¿Por qué lo traigo aquí a colación? Porque el profesor Jay ha publicado el libro bajo licencia GFDL. Y es uno de los libros de introducción a la probabilidad y estadística más asequibles que he visto hasta ahora. Todos los ejemplos que muestra son interesantes y además, vienen con un apartado del estilo: «¿Cómo se hace / calcula esto en R?» (como sabréis los lectores de este blog, R es un lenguaje y entorno de programación para análisis estadístico y gráfico, con licencia GPL) que hace que los conceptos se te queden grabados (la práctica es lo que tiene…)

¿Queréis seguir leyendo el ejemplo de las cartas? Sigamos…

Ten en mente el experimento anterior cuando leas las siguientes secciones de este capítulo (cap. 10 del libro) sobre «Test de hipótesis». Cuando termines de leer el capítulo, vuelve aquí y lee la introducción de nuevo. Toda la jerga matemática que se usa está relacionada con los párrafos anteriores. Mientras tanto, te ayudaré a empezar a pensar en estos términos:

Hipótesis Nula: es una baraja de cartas (baraja inglesa) normal, barajada a conciencia.

Hipótesis Alternativa: o bien es una baraja trucada, o bien el profesor ha barajado con trampas.

Datos observados (muestra de la población): una secuencia de cartas sacadas de la baraja, 5 rojas consecutivas (!)

Si fuera un juego de cartas ordinario, bien barajado, la probabilidad de sacar 0 negras de una muestra de tamaño 5 (sin reemplazamiento) de una baraja de 26 cartas negras y 26 rojas, sería:

> dhyper(0, m = 26, n = 26, k = 5)
[1] 0.02531012

Hay dos temas muy importantes que quedan por tratar. El primero: al final todos los alumnos tuvieron su galleta. El segundo, los estudiantes, agresiva e invariablemente intentan siempre que el profesor enseñe las cartas de la baraja para comprobar si estamos hablando de una baraja normal o no. Nunca lo han conseguido 😉

¿Os gusta? Pues atentos a la jugada: aparte del PDF, el código fuente del libro, en LaTeX, también está disponible. ¿Salivais igual que los candidatos a ganar galletas? Pues leed esto, la traca final:

El profesor G. Jay Kerns, ha grabado en vídeo todas sus clases de introducción a la probabilidad y estadística usando R. TODAS. Y ha dejado los apuntes, vídeos (en distintos tamaños, incluído WebM, y versiones, incluída .3gp, para que puedas atender esas video-lecciones en tu móvil) y anotaciones disponibles para su descarga en la la web de su Universidad, bajo licencia GFDL.

Damas y caballeros, me quito el sombrero ante este señor. Chapeau!

Y por supuesto, aunque me lo he descargado en PDF y fotocopiado, ya he comprado una copia del libro en Lulu.com. Los 31 dólares mejor invertidos desde hace muuuuucho tiempo.