Integración de R en aplicaciones de escritorio. R, Rcom y C#

Hola a todos. Con este artículo espero escribir el primero de una larga serie de artículos sobre el mundo de R. A nuestro juicio, y el de mucha más gente éste es uno de los proyectos GNU con mayor repercusión y también uno de los más prometedores para los usuarios de información geográfica (sigue siendo prometedor, aunque ya es toda una realidad).

Para aquellos que no conozcan R ( http://cran.r-project.org/ ), podemos decir que es un lenguaje de programación a la vez que un paquete estadístico de software, desarrollado bajo licencia GNU GPL de la Free Software Foundation. Lo más interesante de R es que se puede adaptar fácilmente a nuestros intereses mediante la instalación de nuevos paquetes. Hay muchos, y suelen englobar funciones comunes a una misma área de conocimiento. En nuestro caso, existen paquetes relacionados con el tratamiento de la información espacial y más directamente, otros que se relacionan con software GIS. Por poner algunos ejemplos, podemos interactuar desde el GUI de R con SAGA GIS, Grass6, GDAL… y utilizar muchas de sus herramientas, o bien trabajar con otros paquetes propios de R.

En este artículo no trabajaremos desde el GUI de R. Queremos mostrar como integrar R en nuestras aplicaciones de escritorio de .NET mediante objetos COM.

Para poder comenzar, deberemos instalar un servidor COM disponible en http://cran.r-project.org/. Entramos en la sección de software/otros/ e instalamos  R-(D)COM Interface. Por supuesto, también necesitamos tener instalado R 2.8.1. Por otra parte puede ser conveniente instalar un paquete de R llamado rcom con todas sus dependencias.

A partir de aquí, este artículo está dividido en tres partes por motivos didácticos. Primero se habla de cómo se trabaja con Rcom, después describimos cómo se usa el visor de histogramas (que es el ejemplo propuesto), y por último entramos en algunos detalles del código.

Para descargar el código fuente de R2csharp  podéis hacer un checkout del siguiente repositorio Subversion de GIS&Chips:

svn co http://www.gisandchips.org/svn/r2csharp

Uso básico de Rcom

Una vez instalado el servidor COM agregamos todas las referencias a un proyecto WindowsForm  en nuestro IDE de C# y sus correspondientes using (aquí hemos trabajado con Visual C# Express Edition).

using STATCONNECTORCLNTLib;
using StatConnectorCommonLib;
using STATCONNECTORSRVLib;

Con lo que podemos crear nuestro primer objeto de conexión a R, e iniciar una sesión


//Conexión a R
StatConnector sc1 = new STATCONNECTORSRVLib.StatConnectorClass();
sc1.Init("R");

A partir de aquí trabajaremos con tres métodos para interactuar con la sesión de R. Estos son:

  • sc1.EvaluateNoReturn(“código de R”);
  • sc1.Evaluate(“código de R”);
  • sc1.GetSymbol(“nombre de un objeto de R”);

He observado que en ocasiones es indistinto el uso de las dos primeras, pero también podemos recibir una excepción en tiempo de ejecución, por lo que utilizaremos la primera para ejecutar código de R que no tiene porqué devolver ningún resultado (por ejemplo setwd(‘C:/’) , asigna el directorio de trabajo de R), mientras que el resultado de sc1.evaluate() habitualmente querremos almacenarlo en un objeto para poder consultarlo (no tiene sentido hacer un getwd() para después no mostrar su valor, sc1.Evaluate(“wd<-getwd()”), con esto almacenamos el wd en un objeto, el cual podemos consultar desde nuestra aplicación).

Por último, sc1.GetSymbol(“wd”) nos sirve para consultar un objeto creado en nuestra sesión de R y manipularlo. Por ejemplo, podríamos querer mostrar en una etiqueta lblWD la ruta del directorio de trabajo.


string wd = (string)sc1.GetSymbol("wd");
lblWD.Text = wd;

Hasta aquí ya hemos visto todo lo necesario para interactuar con R. Pero la complejidad puede ser mayor debido a las diferencias entre tipos de datos de R y de .NET. Mientras que en R hablamos entre otros de vectores, listas, matrices y dataframes (de números, caracteres…), en .NET tendremos arrays de distintos tipos o tipos simples. Deberemos consultar el tipo antes de almacenar los datos en estructuras de .NET. Esto lo podemos hacer mediante:


txtType.Text = sc1.GetSymbol("wd").GetType().ToString();

donde averiguamos que la función getwd() devuelve un string de .NET. Utilizaremos GetType() muy amenudo. Solamente hay que pensar que estructuras como un dataframe tendrán una estructura en .NET de array de arrays de… por lo que deberemos tener muy en cuenta los tipos de cada vector miembro del dataframe (podemos entender un dataframe como un conjunto de vectores relacionados; cada vector puede ser un campo de la “tabla” que es un dataframe).

R2csharp_histoviewer

Nuestra aplicación es algo más que un “!Hola mundo ¡ “. Tiene ejemplos básicos de distintas tareas habituales en R, pero en este caso realizadas desde nuestra aplicación. En esta demostración creamos un visor de histogramas con Windows Forms, que organiza la información de R de un modo claro y permite crear, mostrar, editar y eliminar dataframes de R, ejecutar una sencilla función de R (“hist( )), y también crear y eliminar ficheros en el sistema operativo (imágenes, directorios…).

Podemos simular una sesión de trabajo con este visor siguiendo estos pasos (también vemos la correspondencia de las acciones en comandos de R):

1. Seleccionar cargar objeto para añadir uno a uno los tres ficheros de ejemplo ( bichos.txt, spatstat.txt y usos.txt)

read.table()

2. Seleccionar el objeto bichos y borrarlo

rm(bichos)

3. Seleccionar un campo en el segundo listbox y crear su histograma      presionando el botón Hist.

hist(objeto$campo) / nos ahorra hacer un attatch() en R

4. Editar una celda del campo “incendio” del objeto usos. Cambiar algún 0 por    100, y creamos de nuevo el histograma. Vemos como ha cambiado el objeto de R sin necesidad de conocer la posición del dato dentro del dataframe. (para   saber que estamos editando en el row del datagridview deberá verse un lapiz sobre el “row head”)

Vista de la aplicación en funcionamiento

Vista de la aplicación en funcionamiento

Evidentemente, sin que el usuario lo sepa se están realizando varios list(), se aplican filtros, se obtienen los rownames() y colnames(), y otras operaciones habituales en R que aquí no se necesitará teclear y cuyos resultados estarán siempre visibles. Lo cual hace que nuestro interfaz sea más amigable solo por esto.

Algunas notas sobre el código:

Entre las tareas más interesantes en el código podemos ver un ejemplo de lectura y escritura de un dataframe en un datagridview, teniendo en cuenta los dos tipos de datos devueltos (enteros y dobles). El fichero de ejemplo spatstat.txt intercala columnas de datos dobles y enteros, claro que también podría haber String [] u otros, pero confiamos en que estas mejoras las puedan realizar nuestros lectores.

En el flujo de trabajo habitual hay dos tipos de objetos, los que contienen nuestros datos y los que utilizamos para interactuar con R. Estos últimos los ocultamos al usuario mediante condiciones “if”.

A la hora de crear imágenes temporales podemos hacer que se muestren en el device de R si no especificamos ningún dispositivo de salida para hist(). Aunque me ha parecido más interesante integrar la gráfica en el formulario. Para esto hay que decir que existe un problema al usar el portapapeles de Windows para almacenar un metafile, que es el único formato que R nos permite. Se trata de una incompatibilidad del SO que no nos permitirá recuperar la imagen del clipboard para mostrarla en el picbox (podemos consultar algo acerca de esta cuestión en http://support.microsoft.com/?scid=kb%3Ben-us%3B323530&x=11&y=12 ) Por este motivo, recurrimos a crear nuestro propio directorio temporal, el cual eliminamos al cerrar el formulario.

Hay que decir que Rcom aporta muchas posibilidades más directas para mostrar o trabajar con los datos de R. No obstante, considero que ya es mucho trabajo conocer un lenguaje de .NET y tener conocimientos de R, como para también especializarse en todas las opciones de Rcom. Para empezar está muy bien, pero en caso de trabajar a menudo con estas herramientas debería explorarse los ejemplos de Rcom, por si resultan más funcionales.

Una consideración que puedo transmitir a los lectores es que no existe ningún “binding” para C# /.NET que nos evite tener que embeber código de R en nuestra aplicación, así como existe rJava (http://cran.r-project.org/web/packages/rJava/index.html ). En caso de disponer de tal posibilidad la hubiésemos utilizado por múltiples motivos, sobretodo por el uso de un solo lenguaje de programación, lo que facilita la comprensión y sencillez del código y también la depuración de la aplicación.

No es necesario advertir que un buen conocimiento de R y las funciones que se quiera aplicar es fundamental para diseñar el mejor interfaz de usuario posible. Pero en determinados casos donde se debe efectuar análisis exploratorios de los datos el esfuerzo se verá compensado por la comodidad y la rapidez en el trabajo. Incluso pensándolo bien, en equipos de trabajo donde haya investigadores o técnicos que no dominen R la creación de un interfaz de este tipo puede ser más que interesante.

Algunas referencias:

En www.CodeProject.com existe un ejemplo de aplicación para C# (http://www.codeproject.com/KB/cs/RtoCSharp.aspx ) donde se repasan las posibilidades básicas para interactuar con R. También hay varios ejemplos de código disponibles para VB6 en la carpeta donde se nos instala el COM Server (por defecto “C:\Archivos de programa\R\(D)COM Server\samples”). Por último, la lista de distribución de Rcom donde se tratan muchas cuestiones relacionadas está en http://mailman.csd.univie.ac.at/pipermail/rcom-l/ .

Datos de ejemplo:

Descargar usos.txt

Descargar spatstat.txt

Descargar bichos.txt

——————————————————————-

Si quereis contactar podeis enviarme un email (asunto: gisandchips):

Benito M. Zaragozí

benito.zaragozi@ua.es

    • Ramon E.
    • 15 junio 2010 10:19am

    Hola Benito,

    Estupendo Blog, un descubrimiento agradable, de verdad.
    Conforme bajo la curva de aprendizaje de R, cada dia lo uso mas, y, sobretodo desde que encontre RExcel (al que considero un estupendo ejemplo de integracion de R en aplicaciones (comerciales).

    Ahora que estoy empezando a olisquear paquetes y funcionalidades mas avanzadas, y he topado con las TclTk…me preguntaba:
    ¿Podría ser que cambiando el punto de vista, se pudiera hacer una aplicación “standalone” desde el propio R (con lenguage S, porsupuesto)?

    Saludos y gracias.

      • benizar
      • 15 junio 2010 12:36pm

      Hola Ramón, me alegro de que participes en el blog.

      En cuanto a lo que preguntas… al decir aplicación “standalone” me queda una duda, ¿te refieres a si es posible crear una aplicación que tome todo lo necesario de R para funcionar de un modo independiente?. Si te refieres a eso, es una conversación que ya he tenido con unos colegas informáticos, que aunque no son usuarios de R pueden tener una idea más acertada que yo de lo que se puede o no hacer con R. En principio no existe ningún IDE pensado para seleccionar las dependencias necesarias, que serían muchísimas para cualquier aplicación. Por otro lado, hacer la selección de dependencias a mano requeriría mucho tiempo y conocimientos sobre R. En mi opinión, creo que vale la pena ahorrar esfuerzos en ese sentido.

      No obstante, si te estabas refiriendo solamente a que R tuviera un buen interfaz gráfico, o permitiera crear uno personalizado, para que no hiciera falta crearlo uno mismo, podrías echarle un vistazo a este proyecto http://wiki.services.openoffice.org/wiki/R_and_Calc . La integración de R en Openoffice parece una salida muy interesante que solucionaría las necesidades de la mayor parte de los usuarios. Tendremos que esperar un poco :-)

      Por favor, hazme saber si te he contestado o si tienes alguna opinión al respecto.

      Un saludo.

        • Ramon E
        • 15 junio 2010 11:34pm

        Gracias Benito, creo que has enriquecido mi opinión.
        Me referia como bien has apuntado, a hacer na aplicación “casi” desde cero atraves de R.
        Por ejemplo: una aplicacion que sea instalable y que aun dependiendo del codigo de R (requiera la instalacion de R o instale las partes necesarias del mismo) tenga una funcionalidad independiente, asi podriamos tener un programa, que hicise uso de algún paquete de R que permite manipular salidas de datos de algun instrumento específico y generar una salida con analis y graficos personalizados.

        Bueno no se si me he explicado, es que al empezar a leer la documentacion del paquete de TcL/TK me he emocionado un poco pues pensé que si hay herramientas para generar GUIs serán por algo…no? :)

        Me gustaría conocer la opinion de otros usuarios expertos como tu de hasta donde se puede llegar con R y si merece la pena profundizar en ello, pues ultimamente estoy usando mucho R profesionalmente.

        Por cierto, conocia RCalc, pero por circunstancias profesionales, me decanté por RExcel.

        Un cordial saludo y exito para tu estupendo Blog.

    • Alfredo CH
    • 9 agosto 2010 4:26am

    Hola.Estoy Comenzando a desarrolla un aplicacion VB.net y con R, pero tengo una duda, de como puedo ejecutar funciones completas de R, por ejemplo :
    en R tengo este Codigo

    BootsUni=function(x,y,B,NivelConf,TipBoots)
    { a=3
    b=2
    suma=a+b
    if(TipBoots==1){
    print(“regular”)
    }
    …….
    ..}

    Ahora la duda es como paso ese codigo a VB.net
    con los comandos EvaluateNoReturn , Evaluate.
    ya probe pero mo me permite varias sentencias…
    como esta si me lo acepta
    sc1.evaluate(“BootsUni=function(){a=3 }”)
    pero si le pongo mas valores me marca error
    sc1.evaluate(“BootsUni=function(){a=3 b=2 }”).

    pero que me pueda ayudar. Muchas gracias
    Muy buena Pagina

      • benizar
      • 13 agosto 2010 3:46am

      Hola Alfredo,
      actualmente estoy de viaje y me llevaría tiempo comprobar lo que propones.

      De todos modos, creo que tiene que ver con que intentas definir varias variables en una línea. Así que, seguramente, basta con que repartas el código de R en varias sentencias, tantas como líneas necesitarías en R.

      Por favor, dime si logras solucionarlo.

  1. Aun no hay enlaces.