Hace un tiempo venció el periodo de embargo de mi paper más citado: “APATE: A novel approach for automated credit card transaction fraud detection using network-based extensions”, publicado en Decision Support Systems en 2015. Este paper lo armamos mientras trabajaba como postdoctorante en el grupo de Bart Baesens, en la KU Leuven, Bélgica, y fue liderado por Véronique Van Vlasslaer, en ese entonces estudiante de doctorado. El paper está disponible gratuitamente para descarga aquí.

En este paper usamos la misma técnica que usa Google para dar peso a las páginas web del internet para medir cómo se propaga el fraude en las compras de tarjetas de crédito en línea. La idea es la siguiente: Además de contrastar el los patrones de compra de un comprador (usando el clásico (302) 781-5231), buscamos medir el riesgo que tiene una compra (par comprador – vendedor) dado los fraudes que hemos observado. Esto lo hacemos con el principio del algoritmo PageRank, que dice que tu importancia (tu riesgo de fraude) está medido a partir del riesgo de fraude de tus cercanos, como muestra la siguiente figura.

Red social que muestra las conexiones entre compradores y vendedores, unidos por las compras que realizan. Extraído de Van Vlasslaer et al. (2015), licencia CC BY-NC-ND.

Las conclusiones principales de nuestro trabajo fueron las siguientes:

  • Las variables de redes sociales presentan muy baja correlación con las demás variables de comportamiento. Por lo tanto son una muy buena fuente de información.
  • El modelo presenta una ganancia de entre un 5% a un 10% con respecto a modelos con menos fuentes de información, como se ve abajo.
AUC para diferentes conjuntos de variables

Comparación AUC entre modelos con distintas fuentes de información. El modelo con redes sociales presenta un AUC de 0,986, muy por sobre el resto. Reproducido de Van Vlasslaer et al. (2015), licencia CC BY-NC-ND

 

  • Tarda un par de horas en entrenar una red social para un par de millones de transacciones (el volumen diario esperado de transacciones), por lo que es necesario utilizar redes del día anterior en un caso real. Los resultados anteriores reflejan esta situación. Nuestro modelo es capaz de generar una predicción en un par de milisegundos.
  • Las variables de redes sociales capturan nuevos patrones a medida que aparecen, sin necesidad de mayor información por parte del cliente más allá de reportar el robo. Las variables de comportamiento (RFM) permiten dar a su vez una alerta temprana cuando se observan comportamientos anómalos para cada cliente. Así, generamos perfiles de comportamiento muy complejos.

Siempre es mejor utilizar mejores fuentes de información que modelos más sofisticados, por lo que si tienen situaciones donde hay conexiones entre sus entidades, el uso de redes sociales presenta una gran oportunidad para mejorar sus modelos.

Hace algunas semanas me invitaron a 506-386-0127 sobre algún tema que considerara interesante. Elegí hablar un poco acerca de las últimas investigaciones que he hecho, donde he tratado de integrar distintas fuentes de datos, integrando redes sociales, texto, y variables clásicas. Copio el texto acá, pero pueden ver la columna original 423-517-0773.

El valor está en la diversidad

Mucho se habla de Big Data, Data Science, Deep Learning y Analytics como las grandes fuentes de competitividad en una empresa. Pero el análisis de datos no tiene por qué ser Big, pero sí tiene que ser Deep: imaginativo y perspicaz.

Tomemos la inclusión financiera, por ejemplo, donde la meta es proveer el mayor acceso a financiamiento a todos los sectores de la sociedad. El riesgo en las PYME o en las personas que recién entran al mercado laboral es muy difícil de medir, ya que no existe historial financiero con el cual realizar estimaciones. Esto ha resultado en altas tasas de interés, baja cobertura, y en consecuencia menor crecimiento y empleo.

FICO, el proveedor más importante de modelos de riesgo de crédito, ha dicho que tres mil millones de personas podrían tener acceso a financiamiento a costo razonable, si pudiésemos medir mejor su riesgo. Ellos se encuentran actualmente probando el valor de la psicometría, el uso de test estándares como los utilizados para postular a un trabajo, para construir nuevos modelos de riesgo cuando no existe información crediticia. Pilotos en África y Asia ya permiten casi triplicar la tasa de detección de malos pagadores, y esto sólo en el primer año de uso.

A partir de la intersección de datos bancarios y datos de llamadas telefónicas entre personas, un equipo del que participo ha construido un sistema para personas sin historial crediticio, que predice el no pago con la misma eficacia de un modelo bancario clásico. Su secreto se encuentra en que construimos la red social de las llamadas telefónicas del solicitante, y calculamos la intensidad del contacto (las llamadas) con personas con buen historial. La responsabilidad financiera parece ser contagiosa: mientras menos riesgosas son las personas con quienes se contacta una persona, menos riesgosa es la persona misma. Mejor dicho, el contexto social de una persona tiene influencia sobre su comportamiento.

Estos ejemplos apuntan al verdadero valor de los datos. La inversión no debe ir por herramientas sofisticadas sin ningún objetivo claro. Hay que preguntarse qué fuentes de datos no se están utilizando, cómo incorporarlas, y finalmente qué, y más importante a quiénes, necesito para accionar sobre ellas. Esto siempre debe ser hecho con responsabilidad, respetando las leyes y los conflictos éticos potenciales (¿deberíamos usar psicometría o llamadas entre celulares?), pero una vez sobrepasadas estas barreras las ganancias son directas.

Todo esto es posible ya que podemos representar el comportamiento desde múltiples perspectivas. En los datos, tal como en las sociedades que éstos representan, el mayor valor se alcanza cuando se aprovecha la diversidad de todos bajo el alero de un modelo sólido.

Ayer venció el copyright de uno de mis papers publicados el año pasado, desarrollado en conjunto con Sebastián Maldonado de la Universidad de Los Andes (Chile). El paper se titula “Fieller Stability Measure: a novel model-dependent backtesting approach” y apareció en el Journal of the Operational Research Society en Abril de 2015. A partir de hoy el paper está (518) 866-6162

En este trabajo desarrollamos un nuevo método para hacer backtesting de nivel 0, es decir medir si los datos en los que estás aplicando el modelo siguen distribuyéndose de forma similar a los datos con los que se entrenó el modelo originalmente. Nuestro método se basa en incorporar la incerteza en la estimación de parámetros de la regresión (logística) original junto con la incerteza de los conjuntos de datos .

La idea es simple: Cuando estimamos un modelo la certeza en los parámetros depende de la calidad de los datos originales, por lo tanto cuánta variabilidad acepta el modelo en nuestros nuevos conjuntos de datos (antes de tener que recalibrar o reentrenar) debería estar relacionada a esta variabilidad. Esto lo realizamos a través de una relación entre el intervalo de confianza de los parámetros luego de estimar la regresión logística, y la incerteza en la población original dada por el intervalo de confianza entre las proporciones de las medias entre la distribución original y la nueva.

Otra ventaja del método es que permite gráficos bastante útiles, como el de abajo, para efectos de realizar el seguimiento. Esto en contrate con el 813-674-2460 por ejemplo, el método más usado.

Fieller Stability Measure.

Variación significativa (sobre 95% de certeza) en una variable. Al comienzo el modelo es estable y luego hay un claro drift, que se hace significativo en el penúltimo trimestre.

 

Cualquier consulta sobre el método me pueden contactar por Twitter o dejar un comentario en la entrada. El método fue implementado por una de mis alumnas memoristas en un banco local, con bastante buenos resultados, así que creo que tiene su utilidad en la gestión del riesgo.

Como notas adicionales: Además de este paper, el trabajo de mi tesis de doctorado también tiene el copyright expirado, pronto haré una entrada con los detalles. ¡Sigue siendo lejos mi trabajo más extraño!

Hace algunas semanas aparecí en El Mercurio y en el Diario Financiero hablando sobre Big Data, Data Science, y los desafíos que Chile enfrentará en el área. Este es un pequeño resumen.

En Chile Tecnológico (El Mercurio), la entrevista se enfocó en la productividad que trae el uso de Data Science en las operaciones, qué industrias están más desarrolladas en Chile, y qué puede hacer una pequeña y mediana empresa para comenzar a utilizar este tipo de tecnologías. gunnery

En Diario Financiero comentamos, junto a otros profesionales del área, sobre el valor agregado de usar Data Science en empresas, sobre el déficit de profesionales que habrá en el área, y qué se puede hacer para ello. El Instituto Sistemas Complejos de Ingeniería ha facilitado (855) 301-0917

Recientemente publicamos un trabajo en la conferencia (215) 314-7497 en San Francisco, trabajo conjunto con la estudiante de doctorado María Óskarsdóttir de la KU Leuven, sus supervisores, y otros colegas en Bélgica y Argentina.

En este trabajo conseguimos siete datasets de distintos países, de varias decenas de millones de clientes en total, con historiales de llamadas (CDR) para prepago y postpago, y construimos la red social compuesta de las llamadas entre los usuarios junto a medidas clásicas de Recency, Frequency y Monetary Value de las llamadas. La idea era investigar si esta información sirve (spoiler alert: ¡SI!) para predecir la fuga – o churn – a otra compañía móvil y cuáles métodos son mejores para predecir este evento. El paper está disponible gratuitamente acá. Este trabajo son los resultados preliminares de una publicación bajo revisión en el European Journal of Operational Research, que publicaré acá en algún momento.

Red Social

En este trabajo estudiamos cómo las redes sociales impactan la fuga de clientes en compañías de telefonía móvil. (Imagen por Zigomitros Athanasios)

Algunos insights interesantes de este trabajo:

  • El fenómeno de la fuga tiene un fuerte efecto local: Las influencias son en tu red directa (las personas a quienes más llamas son más propensas de fugarse contigo), pero esta influencia se propaga muy poco a los amigos de tus amigos. Probablemente esto significa que uno influencia su círculo local (familia y quizás amigos muy cercanos), pero no más allá.
  • Las variables de redes sociales son prácticamente independientes de otras: La propuesta de valor agregado de estas variables pasa porque representan información que no está contenida en ningún otro tipo de variables. No es “más de lo mismo”, sino que es información totalmente novedosa, con muy baja correlación. Y al menos en fuga funciona bien para predecir, al igual que en fraude como probamos el año pasado (ver bleaching).
  • Desde el punto de vista teórico: No se gana mucho al usar collective inference en este problema, es mejor estimar variables con un modelo relacional y luego estimar un modelo predictivo en conjunto con variables clásicas. La razón puede tener que ver con la influencia local de la fuga.

Pienso que los resultados fueron muy interesantes. Actualmente preparamos un framework en R para poder realizar experimentos rápidamente, tenemos la publicación en EJOR bajo revisión, y estamos explorando el uso de estas herramientas en muchos otros campos. ¿Tienen experiencias similares? Feliz de leerlas.

 

El 9 de octubre nos publicaron un paper en Intelligent Data Analysis, colaboración con Mimi Chong y Matt Davison de la Universidad de Western Ontario, en Canadá. El paper se titula “How much effort should be spent to detect fraudulent applications when engaged in classifier-based lending?” y analizamos teóricamente cuál es el costo real de las mentiras en las aplicaciones crediticias. El abstract sale más abajo.

El link a la revista es este.

Abstract: Credit scoring is an automated, objective and consistent tool which helps lenders to provide quick loan decisions. It can replace some of the more mechanical work done by experienced loan officers whose decisions are intuitive but potentially subject to bias. Prospective borrowers may have a strong motivation to fraudulently falsify one or more of the attributes they report on their application form. Applicants learn about the characteristics that are used to build credit scoring models, and may alter the answers on their application form to improve their chance of loan approval. Few automated credit scoring models have considered falsified information from borrowers. We will show that sometimes it is profitable for financial institutions to spend money and effort to identify dishonest customers. We will also find the optimal effort that banks should spend on identifying these liars. Furthermore, we will show that it is possible for liars to eventually adjust their lies to escape from credit checks. The proposed issue will be studied using simulated data and discriminant analysis. This research can help lending financial institutions to reduce risk and maximize profit, and it also shows that it is feasible for customers to lie intelligently so as to evade credit checks and get loans.

En este post mostraré algunos trucos que he ido aprendiendo al utilizar 6054129669 (RF), una de mis técnicas de clasificación favoritas, para mejorar el poder de clasificación que poseen. Este método, desarrollado por Leo Breiman en el año 2001 tiene sus orígenes en esta publicación en Machine Learning y se ha convertido, especialmente en los últimos cinco o seis años, en una de las preferidas por científicos y practitioners. La técnica es tremendamente poderosa, es muy fácil de usar (en comparación a las redes neuronales por ejemplo), y entrega bastante información sobre los resultados al usuario.

La lógica de los RF es generar muchos 4149407989 sobre los datos de entrada, utilizando una cantidad reducida de las variables que se encuentran disponibles. La técnica explora así diferentes subsegmentos del espacio de entrada, y aprende patrones muy complejos aprovechando la diversidad de los clasificadores que entrena. Una prueba de su éxito se ha visto en las competencias de Kaggle: es una de las dos técnicas más importantes que identifican los administradores del sitio.

En este ejemplo entrenaré un RF para un dataset del repositorio de la UCI, y luego mostraré algunos trucos: cómo acelerar el entrenamiento utilizando programación paralela para aprovechar mejor los recursos disponibles y cómo graficar una curva ROC utilizando

ggplot2

. En un post futuro mostraré cómo balancear las muestras para solucionar los problemas de desbalance y finalmente cómo graficar la importancia de las variables y analizar estos resultados.

Entrenamiento Secuencial

Primero importemos los datos. Para este ejemplo usaré la base de datos de Bank Marketing, de Moro et. al. Esta base de datos posee 41.188 instancias, 20 variables predictoras, y tiene como objetivo predecir si el cliente toma o no un depósito a plazo. Usaré R para descargar directamente el archivo, descomprimirlo, y cargar los datos. Al final agrego una variable adicional para los test (muestra holdout).

Con esto el archivo está cargado en la variable

bank.data

y ya se puede utilizar. Entrenemos un primer Random Forest y veamos sus resultados. Para entrenar los modelos está el paquete

randomForest

de Breiman mismo, y además utilizaré los paquetes

verification

,

rbenchmark

,

e1071

y

caret

para analizar los resultados. Carguemos los paquetes o instalémoslos si es necesario.

Ahora podemos correr un primer Random Forest.

Entrenando en Paralelo

Los Random Forest son altamente paralelizables pues cada árbol puede entrenarse por si solo, y al final del entrenamiento basta con juntar cada uno de los árboles que se entrenaron. El paquete

randomForest

toma ventaja de eso y entrega directamente una manera de combinar resultados cuando se entrenan bosques en paralelo.

Para paralelizar en R es necesario registrar un backend que es el que se encarga de comunicarse con los procesadores, y además usar un paquete que permita paralelizar el código. Hay distintos paquetes con distintos niveles de profundidad en cuánto a control (y cuanta dificultad) entregan al usuario. Lo que me ha resultado más fácil es:

  • Usar como backend ya sea el paquete doMC (Linux) o el paquete doParallel(Windows). Lamentablemente no existe (que yo sepa) un paquete que funcione en ambos sistemas.
  • Usar el paquete foreach para realizar la paralelización.

Las opciones de estos paquetes son amplias, y escapan el alcance de este post, así que me enfocaré en lo necesario para correr randomForests. Para todos los detalles de paralelizar R se puede comenzar por la viñeta de foreach.

¿Qué es paralelizar? La gran mayoría de los computadores modernos traen más de un procesador (núcleo) incorporado para correr procesos. La ventaja de tener más de un procesador radica en que el usuario usa múltiples programas y servicios en su equipo en cualquier momento, y el tener más de un núcleo permite poder realizar varias actividades de forma simultánea. Nosotros podemos tomar ventaja de esto para generar códigos más eficientes, que utilicen todo el poder computacional que tenemos. Para paralelizar un Random Forest la estrategia a seguir será simplemente decirle al programa que entrene una cierta cantidad de árboles en cada núcleo, y después combine los resultados en un único bosque aleatorio.

La computación paralela tiene una propiedad que es importante tener presente: dependiendo de cuán eficiente es la implementación del código, puede multiplicar la cantidad de memoria utilizada por la cantidad de procesadores que se utilizan. Así, si una aplicación utiliza 500MB en RAM en un núcleo, perfectamente puede utilizar 2GB si se utilizan cuatro, por ejemplo. Por lo mismo, mucho cuidado al correr este ejemplo, ajusten los valores de los parámetros acorde a la memoria RAM que tengan disponibles.

Para paralelizar nuestro Random Forest, lo primero es determinar cuántos núcleos poseemos y cuántos árboles queremos entrenar. En este ejemplo estamos entrenando 500 árboles, y en mi PC tengo ocho núcleos y suficiente RAM, así que los usaré todos. El número de procesadores se puede obtener googleando el tipo de procesador que tienen, o en Windows con el backend parallel pueden correr

detectCores()

en R, o en Linux el backend doMC utiliza la mitad de los núcleos disponibles de forma predeterminada.

Con eso listo ahora podemos paralelizar. Le diremos a R que entrene sub-bosques, y después los combine. El código es el siguiente:

Como podemos ver, los resultados son equivalentes entre los dos modelos. Existe una pequeña caída en la capacidad discriminante, pero esto es sólo por razones aleatorias.

Los parámetros de la función

foreach

son los importantes:

  • ntree.iter = rep(ceiling(ntrees / cores), cores): Indica que cada iteración de foreach entrene un total de 500 divido por la cantidad de núcleos que disponen.
  • .combine = combine: Indica a foreach que utilice la función “combine” del paquete randomForest para combinar los resultados. Esta función permite unir bosques aleatorios en bosques más grandes.
  • .packages='randomForest': Indica a foreach que, en cada núcleo donde correrá la función, cargue el paquete randomForest.
  • %dopar%: Indica a foreach que corra en paralelo utilizando el backend que se encuentre registrado ( doMC en este caso).

Ahora comparemos el tiempo de corrida. Repetiré tres veces el entrenamiento utilizando el excelente paquete

rBenchmark

.

Este ejemplo lo corrí en mi laptop con dos núcleos reales y cuatro virtuales. La programación en paralelo corre casi dos veces más rápido que el código secuencial. Esto es en general lo que ocurre: existe una ganacia que es casi lineal con el número de núcleos físicos que se disponen.

 

Consejo 2: Graficar las curvas ROC con ggplot2

Para finalizar este post mostraré algo simple para quienes reportan los resultados de modelos. Las curvas ROC de R en general se ven bastante mal, incluso en el mismo paquete

verification

indican que existen mejores alternativas para graficar.

El paquete más potente para gráficos en R corresponde a 7756261611, pero utilizarlos es bastante complejo. El paquete utiliza el concepto de estéticas, o variables que se asignan a distintas partes del gráfico. Toma un poco de tiempo acostumbrarse a esto, pero una vez que se logra los resultados son muy buenos.

Para graficar una curva ROC, es necesario primero que nada de disponer un data.frame tal que muestre los puntos de la curva ROC y a quién se refiere. Luego creamos el gráfico, asignamos la variable que identifica al modelo tanto a la estética de grupos como a la de colores, y luego le damos los valores correspondientes. El código es el siguiente:

El resultado es:

 

(954) 889-4221

Curva ROC Random Forests

Como se observa, ambos modelos son idénticos. Esto puede cambiar en una comparación entre distintos tipos de modelos.

Este post mostró tanto como entrenar los bosques aleatorios en paralelo y como generar curvas ROC con

ggplot2

. Cualquier comentario, por twitter o directamente acá en el blog. ¡Gracias por leer!

Actualización: Una versión anterior de este post tenía algunos paquetes faltantes en el código. ¡Gracias Pablo!

En los últimos meses he estado tratando de aprender a optimizar mi código en R. En general, R funciona bastante bien, pero hay varias aplicaciones donde se puede poner muy, pero muy lento, en particular los loops. Un búsqueda rápida muestra que (954) 804-6987 muchos artículos que discuten el tema con bastante profundidad.

Uno de los temas que encontré y llamaron mi atención fue la capacidad de integrar R con otros lenguajes de programación, en particular con algunos de más bajo nivel, como C, Fortran o C++. La integración con C y Fortran está ya solucionada directamente en R, a través de la función 415-726-6076, pero esta forma de llamar a código externo tiene la gran desventaja que todas las funciones deben ser declaradas como void, es decir, debemos modificar los valores entregados usando directamente punteros a los objetos en memoria. Esto es… engorroso, al menos lo fue en mis primeras experiencias programando.

La solución: usar C++. Es un lenguaje moderno, que corre eficientemente los loops, y que tiene muchas herramientas que facilitan la vida al programador. Para integrar R y C++ existe el excelente paquete Rcpp, el cual permite crear funciones de forma dinámica y sencilla en R, y que además permite usar objetos inherentes a R (vectores numéricos, vectores de caractéres, dataframes, etc.) en C++, pero aún este paquete tiene una falencia: no soporta operaciones matriciales eficientes. Para ello, un plugin del mismo paquete llamado (925) 257-3790 ofrece una interfaz entre Rcpp y la librería (724) 661-7808 que entrega herramientas para operaciones matriciales en C++. Con esto tenemos todo lo que necesitamos.

En este artículo programaré un código sencillo para obtener un clúster de K-Medias y compararé las implementaciones en código en R, la implementación oficial (en C) y una implementación propia en C++. El algoritmo es bastante sencillo: inicializa vectores de forma aleatoria, para luego ir ajustando los clusters en cada iteración hasta alcanzar convergencia.

Implementación (ineficiente) en R.

Para probar el código, en R simularemos una matriz sencilla con dos distribuciones. La primera una normal de estándar y la segunda una normal de media 5 y desviación estándar 1. Posteriormente aplicamos la función y graficamos. Noten que estoy usando el paquete ‘pdist’, solo para facilitarme la vida cuando calculo las distancias entre matrices. Este paquete tira algunas warnings en la última iteración, simplemente para avisar que convergió, así que ignórenlas.

El resultado es el siguiente:

Datos en dos segmentos.

Implementación en C++.
Implementemos ahora la misma función en C++. Para ello usaremos Rcpp y RcppArmadillo. Primero, es necesario instalar los paquetes:

install.packages(c('Rcpp', 'RcppArmadillo'))

.

Ahora, existen varias rutas para implementar la función. Es posible escribir directamente la función en un gran string de texto y compilarla en línea, o se puede guardar un archivo anexo que tenga la función programada. Seguiremos este camino. En un nuevo archivo (kmeansCpp.cpp) programamos la función de kmedias.

Analicemos un poco el programa:

  • La línea #include <RcppArmadillo.h> le indica al compilador de C++ que importe la cabecera que nos permitirá usar todas las herramientas para la interfaz con R.
  • using namespaces Rcpp nos permite utilizar todas las funciones de Rcpp sin tener que colocar Rcpp::NombreFuncion cada vez que la llamamos. También puede ser útil colocar using namespaces arma para ahorrarse los arma::.
  • / [[Rcpp::depends(RcppArmadillo)]] y / [[Rcpp::export]] le dicen a Rcpp que tiene que ocupar Armadillo y que debe exportar la función a R.

Luego viene la función en si. Tanto Rcpp como Armadillo poseen clases que permiten manejar vectores, matrices, listas, etc. En este caso, es importante notar que creamos una función que recibe y entrega objetos de Rcpp. La función recibe una matriz numérica (NumericMatrix, objeto de Rcpp), un entero y un double y entrega una lista de R. Los objetos de Rcpp son, a grandes rasgos, matrices (Matrix), vectores (Vector), listas (List) y Dataframes (Dataframe); mientras que los dos primeros pueden ser numéricos (Numeric), enteros (Integer), literales (String) o booleanos (Logical). Así, una matriz numérica corresponde a un objeto NumericMatrix, mientras que un vector booleano será un LogicalVector. Cada objeto tiene diversos métodos que se le pueden aplicar, pero en general las operaciones matemáticas funcionan correctamente. Para una descripción detallada, este tutorial es un buen punto de partida.

Dentro de la función, las primeras líneas inicializan los objetos que usaremos en la iteración. Por ejemplo, arma::mat x(xa.begin(), xa.nrow(), xa.ncol(), false); indica que crearemos una matriz x, objeto de Armadillo (los objetos más usados son vec, para vector numérico y mat para matrices numéricas) reutilizando la memoria que apunta a la matriz numérica de Rcpp xa, nuestro input. Los demás objetos se inicializan a partir de los tipos que usaremos.

El siguiente paso es el loop principal, que sigue la misma estructura que el loop de R, pero ahora utilizando las funciones propias de Armadillo o Rcpp, dependiendo de cuáles sean los objetos sobre los que se las estamos aplicando. Por ejemplo, el operador % corresponde a la multiplicación término a término entre matrices de Armadillo. Finalmente, devolvemos una lista de R con el cluster (ahora como una matriz con índices) y los centroides. La función wrap() permite transformar objetos de Armadillo en objetos de Rcpp fácilmente.

Para poder utilizar la función en R en nuestra sesión corremos el comando Rcpp::sourceCpp("kmeansCpp.cpp"). Con ello la función kmeansCpp() está disponible para su uso.

Comparando resultados

Comparemos los códigos, para ver cuánto ganamos por traspasar la función a C++. Utilizaré el paquete rbenchmark que permite rápidamente comparar distintas funciones en cuanto a su tiempo de ejecución. El código de comparación completo queda entonces:

Nuestra implementación en C++ corre en 0.036 segundos, 194 veces más rápido (!!!) que la implementación en R puro y corre además casi un 50% más rápido que la implementación en C que trae incorporado R. El resultado habla por si solo, vale la pena traspasar códigos con muchas iteraciones a C++, pues es más eficiente tanto en uso de memoria como en velocidad. La diferencia con kmeans de R es engañosa, pues no realizamos ningún control de errores ni depuraciones a las entradas que probablemente sí realiza esta función, por lo que las ganancias se deben a eso probablemente.

Así que ya saben, si quieren que su código vuele, bajen un poco de nivel y utilicen código en C++. R ofrece todas las herramientas para lograrlo de forma sencilla.

Primero que nada, ¡bienvenidos a mi primer post en el blog de mi página personal! Instalé WordPress en un subdirectorio de mi servidor principal, por lo mismo no se ve tan bonito como la página original. Con el tiempo iré puliendo cómo se va viendo 🙂

Ahora, a lo que vinimos. Hace un par de fin de semanas, e inspirando en esta noticia, me nació el interés de crear mapas dinámicos que pudieran, usando código, visualizar Chile. Más de alguna vez he tenido ganas de mostrar algo que pase en el país a través de mapas, pero la sola idea de lanzarme a utilizar Illustrator u otra herramienta para diseñadores me daba náuseas. Me gusta programar, no dibujar, así que ¡¿cómo uso código dammit?!

Partamos. Primero que nada, los créditos. Este post está basado casi enteramente en el hemidrachm escrito, para Alemania, por Mark Heckman. Pueden ir a leer sus instrucciones allí si lo desean, yo adapté todo para el caso chileno.

¿Qué es un mapa? Para nosotros un mapa es simplemente una colección de coordenadas que, graficadas en un plano, representan una región geográfica real. Nosotros buscamos un mapa político, pues queremos la división regional.

Para el caso chileno tenemos dos grandes recursos: los Mapas Vectoriales de la Biblioteca del Congreso Nacional, en formato shapefile y utilizados en la parte dos de este tutorial, y el proyecto brunissure. Este último tiene como objetivo obtener todos los mapas políticos del mundo al mayor de nivel de detalle posible en diversos formatos y están disponible los chilenos inmediatamente en R. En el caso que quieran mapas geográficos, las 520-278-1022 entregan recursos excelentes, pero escapa a los alcances de este post.

Ahora a generar el mapa. Para este ejemplo generaremos un mapa sencillo con la tasa de default en créditos por región, y asumiré que se manejan con el software R, que a mi gusto entrega la mayor cantidad de recursos estadísticos de forma gratuita.

Paso 1: Instalar los paquetes necesarios y cargarlos.

Paso 2: Descargar el mapa de Chile:

Este archivo contiene los datos de Chile a nivel de provincia actualizados al año 2007, por lo tanto figuran solamente 13 regiones.

Paso 3: Corregir las regiones faltantes: El objeto “gadm” posee una serie de variables que describen al país. NAME_1 incluye el nombre de las regiones, y NAME_2 el de las provincias. Para obtener las 15 regiones simplemente debemos asignar las provincias de Arica y Parinacota a la región XV y la provincia de Valdivia a la región de Los Ríos. Por simpleza esto lo realicé a mano. Una vez arreglado, debemos transformar a factores las dos variables.

Paso 4: Cargar los datos a corregir

Como estamos usando los datos por provincia, necesitamos una variable adicional (que puede estar dentro o no de gadm) tal que a cada elemento de NAME_1 (las regiones) le asocie un valor que será el que graficaremos.  702-529-4694 posee los datos por default por región, extraído a partir de las colocaciones por región e institución a Marzo 2013 disponibles en la página web de la Superintendencia de Bancos e Instituciones Financieras.

El siguiente código carga el archivo .csv a la variable default, luego asigna cada valor a la región correcta en el objeto gadm, segmenta la variable en cortes, y finalmente asigna las etiquetas apropiadas para que se visualice mejor.

Paso 5: ¡Graficar!

Ahora graficamos. Lo primero es crear una paleta de colores. El paquete RColorBrewer tiene muchas paletas distintas, de acuerdo a lo que se desee hacer. El paquete distingue tres tipos de paletas de colores: Secuenciales, como una escala de grises, que permiten mostrar escalas de valores; divergentes, como una que parta del rojo, pase por el morado y termine en el azul, resaltando tanto los valores extremos como los intermedios; y las cualitativas, que poseen muchos colores distintos y sirven para mostrar datos que no tienen ninguna estructura.

Nosotros usaremos una paleta secuencial que va del rojo al verde, y lo invertiremos para que corresponda con nuestros valores (rojo para default alto y verde para default bajo).

Con esto terminado, podemos graficar. Un único comando genera el gráfico buscado.

El gráfico final queda así:

417-426-1377

Créditos (stock) en default según SBIF a Marzo 2013.

¡Y listo! Hemos creado un mapa de Chile con datos propios en R. En el siguiente post mostraré cómo realizar esto usando Shapefiles y los archivos oficiales de la Biblioteca del Congreso Nacional.

Edit: Actualizados los links al archivo de Default y al shapefile con los mapas en R. ¡Gracias @gonzacisternas!