En las III jornadas de R tuve el placer de asistir al taller de Gregorio Serrano sobre informes con R. Me abrió los ojos. Siempre he pensado que R no es una herramienta que sirva para hacer informes (modo consultor = ON); R no servía para realizar reporting (modo consultor = OFF). Pero R tiene un poderoso motor gráfico y dispone del paquete R2HTML para poder realizar tablas en HTML; y si trabajamos con libros CSS de estilos podemos obtener resultados muy atractivos. Así que la otra tarde me puse manos a la obra y creo que puede salir una trilogía interesante. Bueno, depende del interés que despierte esta entrada del blog haré más entregas, pero de momento tengo en mente llegar a 3.

Seguimos con el sistema habitual. Simulo unos datos de ejemplo que podéis copiar y pegar en vuestra consola de R:

clientes = 20000
saldo_vista = abs(rnorm(clientes, 0, 1) * 10000 + 5000)
saldo_ppi = (runif(clientes, 0.1, 0.6) * rpois(clientes, 2)) * 60000
saldo_fondos = abs(rnorm(clientes, 0, 1) * 100000 + 3000) * (runif(clientes) >= 0.6)
edad = rpois(clientes, 60)

datos_ini <- data.frame(cbind(saldo_vista, saldo_ppi, saldo_fondos, edad))
datos_ini$saldo_ppi = (edad < 65) * datos_ini$saldo_ppi

# Creamos la variable objetivo a partir de un potencial
datos_ini$potencial = runif(clientes, 0, 1)
datos_ini$potencial = datos_ini$potencial +
  log(edad) / 2 +
  runif(1, 0, 0.03) * (saldo_vista > 20000) +
  runif(1, 0, 0.09) * (saldo_fondos > 30000) +
  runif(1, 0, 0.07) * (saldo_ppi > 10000)

datos_ini$pvi = (datos_ini$potencial >= quantile(datos_ini$potencial, 0.85)) * 1

# Eliminamos la columna que genera nuestra variable dependiente
datos_ini = subset(datos_ini, select = -c(potencial))

Datos simulados de una entidad bancaria donde tenemos edad, saldos en distintos productos de pasivo e identificamos a aquellos clientes que tienen contratada una pensión vitalicia. Nos solicitan realizar un informe con los datos de contratación por edad y por pasivo. Cuando realizamos informes es muy habitual tramificar variables continuas. Para crear los tramos de edad y de pasivo vamos a emplear la función recode de la librería memisc:

# Con memisc recodifico los factores
library(memisc)

datos_ini$rango_edad <- recode(datos_ini$edad,
  "1 Menos de 45 años" <- range(min, 45),
  "2 Entre 46 y 55 años" <- 46:55,
  "3 Entre 56 y 65 años" <- 56:65,
  "4 Más de 65 años" <- range(66, max))

datos_ini$rango_vista <- recode(datos_ini$saldo_vista,
  "1 Menos de 5.000 €" <- range(min, 5000),
  "2 Entre 5.000 y 15.000 €" <- range(5000, 15000),
  "3 Entre 15.000 y 25.000 €" <- range(15000, 25000),
  "4 Más de 25.000 €" <- range(25000, max))

Los intervalos creados son cerrados por la derecha. En el blog se ha tratado en otra ocasión la recodificación de los factores y no se trabajó con memisc. Bajo mi punto de vista, recode + memisc es la mejor opción. Ya tenemos nuestras variables recodificadas y ahora tenemos que sumarizar y graficar el número de clientes frente a las tasas de contratación. A la hora de realizar informes, los formatos son muy importantes. Por defecto, en R estamos acostumbrados a trabajar con formatos americanos (puntos para decimales y comas para miles). Esto a mí no me gusta; prefiero el formato europeo. Por ello, lo primero que hacemos es crearnos unas funciones que nos den formatos europeos y formatos en porcentaje:

# Función para dar formatos a los datos
# Separador de miles europeo
sep.miles <- function(x) {
  format(x, big.mark = ".")
}

# Creación de formatos de decimales
fmt.porcen <- function(x) {
  paste(format(round(x, 2), decimal.mark = ","), '%')
}

Estas funciones nos servirán para dar formatos a los números de nuestras tablas. ¿Cómo vamos a hacer las tablas? Con ddply, por supuesto. Ahora las librerías plyr y ggplot2 son las que nos ayudarán a crear el informe:

library(plyr)
library(ggplot2)

# Realizamos la tabla de sumarización
resum1 <- ddply(datos_ini, "rango_edad", summarise,
                clientes = length(rango_edad),
                contrata = sum(pvi))

resum1$tasa = fmt.porcen(resum1$contrata * 100 / resum1$clientes)
resum1$clientes = sep.miles(resum1$clientes)
resum1$contrata = sep.miles(resum1$contrata)

# Pintamos un diagrama de barras
png(file = "C:\\temp\\informes\\resum1.png", width = 600, height = 450)
a <- ggplot(datos_ini, aes(rango_edad, fill = factor(pvi)))
a + geom_bar()
dev.off()

resum2 <- ddply(datos_ini, "rango_vista", summarise,
                clientes = length(rango_edad),
                contrata = sum(pvi))

resum2$tasa = fmt.porcen(resum2$contrata * 100 / resum2$clientes)
resum2$clientes = sep.miles(resum2$clientes)
resum2$contrata = sep.miles(resum2$contrata)

png(file = "C:\\temp\\informes\\resum2.png", width = 600, height = 450)
a <- ggplot(datos_ini, aes(rango_vista, fill = factor(pvi)))
a + geom_bar()
dev.off()

Mucho código. Los objetos resumx son las tablas que hemos de representar; son sumarizaciones del total de clientes y de los clientes que contratan el producto. Calculamos una tasa y aplicamos los correspondientes formatos. Al formatear los datos, los números pasan a ser texto; en ese sentido R no es como otras herramientas: no provoca muchos problemas. El último paso es realizar el informe. Todo quedará almacenado en nuestro disco; en este caso trabajamos con Windows y guardamos el informe en C:\Temp\informes:

library(R2HTML)

salida = HTMLInitFile("C:\\temp\\informes", filename = "salida",
                      CSSFile = "C:\\TEMP\\informes\\table_design.css")

HTML("<div align=center>", file = salida)
HTML("<p align=center>Estudio por edad</p>", file = salida)
HTML(resum1, file = salida)
HTML("<p align=center>Clientes por rango de edad</p>", file = salida)
HTML("<img src='c:\\temp\\informes\\resum1.png'></img>", file = salida)
HTML("<p align=center>Estudio por saldo a la vista</p>", file = salida)
HTML(resum2, file = salida)
HTML("<p align=center>Clientes por saldo a la vista</p>", file = salida)
HTML("<img src='c:\\temp\\informes\\resum2.png'></img>", file = salida)
HTML("</div>", file = salida)

HTMLEndFile()

El objeto salida es una página estática HTML que llama a una hoja de estilos; con esto podemos realizar tablas más bonitas y espectaculares. Esta página se crea con la función HTMLInitFile; con la función HTML ya introducimos código HTML a salida hasta que encontramos HTMLEndFile. Yo no soy ningún experto en HTML; creo que sería mejor decir que no tengo ni idea, pero con Google y R2HTML vamos a crear informes tan bonitos como este.