Como veníamos hablando en entradas anteriores del Blog, R es un lenguaje y un entorno de programación para análisis estadístico que se está convirtiendo rápidamente en una herramienta de referencia para el análisis espacial y la geoestadística.
R trabaja con datos que se almacenan en la memoria en nuestro ordenador. Esto puede llegar a suponer un gran problema para un usuario que trabaje en una computadora con una memoria RAM escasa (menos de 4 u 8 GB). Ya que, como es habitual en el trabajo con datos espaciales o en big data, nos enfrentaremos a casos prácticos en los que será necesario gestionar una gran cantidad de información que bloquearán la memoria de nuestro sistema operativo.
Es complicado establecer un límite para considerar cuando estamos procesando «un gran tamaño de datos». Esta entrada se centra en el procesamiento masivo de datos en R, proporcionando algunas soluciones en aquellos casos en que empezamos a notar que R va más lento de lo normal o cuando nuestro sistema operativo comienza a bloquearse e impedir que trabajemos con normalidad.
1. Paquete data.table
La primera solución propuesta es la utilización del paquete data.table. Este paquete ofrece una «versión mejorada» de los Data Frame que incorpora R base reduciendo su tamaño hasta 10 veces. Además, mejora considerablemente los tiempos de ejecución de lectura, manipulación y exportación los datos dentro de R.
# Instalamos la librería data.table y la cargamos en nuestra sesión install.packages("data.table") library(data.table)
El paquete data.table introduce la función fread() para cargar rápidamente conjuntos grandes de datos.
# Cargamos un conjunto de datos con fread() data <- fread('covid19_tia_muni_y_distritos.csv')
Para poner a prueba la eficacia del paquete en la lectura de datos, hemos empleado el siguiente conjunto de datos:
Casos COVID19 confirmados, casos confirmados con infección activa y tasas de incidencia acumulada (TIA) por municipios y distritos de Madrid.
Puede descargarse del Catálogo de Datos Abiertos de la Comunidad de Madrid en el siguiente enlace. Cómo puede verse en las siguientes sentencias, se consigue reducir casi cinco veces los tiempos de espera.
################################################ # Tiempos de lectura de un CSV con read.csv() # ################################################ system.time(df1 <-read.csv('covid19_tia_muni_y_distritos.csv', header=TRUE, sep = ';')) ## user system elapsed ## 0.104 0.005 0.129 ############################################# # Tiempos de lectura de un CSV con fread() # ############################################# system.time(dt1 <-fread('covid19_tia_muni_y_distritos.csv',showProgress=F)) ## user system elapsed ## 0.020 0.007 0.077
Esto sucede porque la función read.csv() carga las filas en memoria como caracteres y luego las transforma al tipo de datos adecuado, mientras que fread() únicamente lee los datos como cadenas.
También puede utilizarse las funciones as.data.table() o setDT() para convertir otros datos a la clase data.table. En el siguiente ejemplo, vamos a utilizar los datos de todos los vuelos que salieron de Nueva York en 2013. Estos datos los proporciona el paquete de R nycflights13 en el objeto flights, que cuenta con aproximadamente 350.000 registros, con un tamaño mayor al que hemos empleado en el ejemplo anterior.
# Instalamos la librería nycflights13 y la cargamos en nuestra sesión install.packages("nycflights13") library(nycflights13) # Cargamos los datos de los vuelos flights
En el siguiente código podemos ver como convertimos un objeto a la clase data.table y la comparativa del tiempo que conlleva exportar un CSV con R base junto con el tiempo que se tarda en realizar lo mismo con el método fwrite() que proporciona data.table.
# Convertimos a data.frame y a data.table para trabajar df2 <- as.data.frame(flights) dt2 <- as.data.table(flights) ############################################### # Tiempos de escritura de un CSV con fwrite() # ############################################### system.time(write.csv(df2)) ## user system elapsed ## 22.529 0.416 23.639 ############################################### # Tiempos de escritura de un CSV con fwrite() # ############################################### system.time(fwrite(dt2, showProgress=F)) ## user system elapsed ## 0.327 0.046 0.398
El tiempo que se tarda en exportar el fichero con el paquete data.table es hasta 73 veces menos.
La librería cuenta además con muchas funciones para manipulación de datos y un excelente material de ayuda. Para aprender mucho más sobre sobre data.table se puede consultar los siguientes enlaces a su web:
Sin duda una herramienta estupenda para el procesamiento masivo de datos en R.
2. Paquete terra
Cuando trabajamos con archivos ráster, es muy común que necesitemos procesar imágenes de grandes dimensiones. En estos casos, una posible alternativa al uso del conocido paquete raster de análisis espacial es la reciente librería publicada por RSpatial denominada terra.
El paquete terra cuenta con funciones que permiten crear, leer, manipular y escribir datos en el formato ráster. Una de sus principales características es que puede usarse para trabajar con grandes conjuntos de datos que estén almacenados en el disco y que son muy pesados como para cargarlos en memoria. Esto es posible gracias a que el paquete terra crea objetos con información de la estructura de los datos originales (como extensión espacial, número de filas, número de columnas…) pero no almacena los valores de todas las celdas en la memoria. Y por tanto, permite que los datos puedan procesarse antes.
# Instalamos y cargamos el paquete terra install.packages("terra") library(terra)
Puede consultarte más información sobre el paquete terra y ver casos prácticos en la página oficial de RSpatial en el siguiente enlace.
3. Paquete disk.frame
El paquete disk.frame es u paquete de R que también facilita el trabajo con datos que son demasiado grades para la RAM. Su funcionamiento, como se explica en el repositorio oficial del paquete, se resumen en dos ideas:
- Divide un conjunto grande de datos que no es capaz de procesar la RAM en trozos más pequeños dentro de una carpeta y
- proporciona un API para manipular dichos trozos
Se puede instalar el paquete con las siguientes sentencias:
# Instalamos y cargamos el paquete disk.frame install.packages("disk.frame") library(disk.frame)
La librería introduce una nueva clase denominada disk.frame. Y, al igual que ocurría con los data.table, podemos crear objetos del tipo disk.frame desde data.frame o generarlos desde archivos externos como CSV.
En el siguiente ejemplo, vamos a emplear los datos de COVID19 que hemos utilizado con el paquete data.table. Podemos usar la función csv_to_disk.frame() que proporciona la librería para convertir datos de otro clase al tipo disk.frame.
############################################### # Tiempos de lectura de un CSV con read.csv() # ############################################### system.time(df3<-read.csv('covid19_tia_muni_y_distritos.csv', header=TRUE, sep = ';')) ## user system elapsed ## 0.094 0.004 0.132 ########################################################## # Tiempos de escirtura de un CSV con csv_to_disk.frame() # ########################################################## system.time(csv_to_disk.frame('covid19_tia_muni_y_distritos.csv', outdir = '/Users/diana/Desktop/prueba', overwrite=TRUE)) ## user system elapsed ## 0.053 0.010 0.093
Como se puede ver, los tiempos se reducen prácticamente a la mitad lo que facilita el procesamiento masivo de datos en R. Se puede consultar más información y ver el resto de funcionalidades y tutoriales en su web.
Si te ha gustado esta entrada y quieres aprender a trabajar con datos espaciales en el entrono de R, inscríbete ya en el curso online de R y GIS: usa R como un GIS.
Tutora del curso de R y SIG. Grado en Ingeniería en tecnologías de la información y en Geomática y topografía. Máster en Ingeniería y geoinformación. Echa un vistazo a todos nuestros cursos de SIG online.