[R] Cómo extraer información de múltiples archivos

Acostumbrado a tener toda la información en una única tabla o archivo (.csv generalmente), este fin de semana me he topado con un curioso problema. Buscando series temporales históricas de temperaturas en España, he dado con un conjunto de tablas de datos diarios, de manera que cada día estaba almacenado en un archivo diferente.

Así pues, para analizar una serie con algo de sustancia (pongamos tres años de duración, por ejemplo) tendríamos que lidiar con más de novecientos archivos, de los cuales, a lo sumo, querremos extraer uno o dos valores medidos en una estación meteorológica concreta. ¿Cómo resolver esta situación en R?

Nota: si buscamos un poco más, podemos encontrar los datos de interés, agrupados por meses, para el período 1920-2012. Esto, en lugar de aliviar nuestro problema, seguramente provocará que ampliemos el rango de las series temporales, por lo que todavía tendremos que trabajar con bastantes archivos.

Obviamente, escribir el código de extracción de los valores que nos interesan, para cada archivo en concreto, está totalmente descartado. ¿Qué hacer en estos casos? Según mi experiencia, acudir a Stack Overflow, que seguro alguien antes que nosotros ha pasado por esta angustia.

El proceso es más sencillo de lo que esperaba. En primer lugar, nos hacemos con los nombres de los archivos en donde están almacenados los datos de interés. Para ello escribiríamos:


filenames = list.files(path = "data/raw/",
                       pattern = "*.CSV")

Dentro del argumento path escribiremos la ruta donde se encuentren todos los ficheros. Podemos hacerlo de manera abreviada, teniendo en cuenta que siempre el camino será relativo al directorio de trabajo actual de la sesión de R; o bien tecleando la ruta completa, poniendo ahora cuidado en cómo escribir las barras inclinadas, que según el sistema operativo en el que estemos trabajando es diferente.

El argumento pattern contendrá una expresión regular que se ajuste a los nombres de los archivos con los que queremos trabajar. Para evitar la más que posible frustrante pelea con las expresiones regulares, recomiendo que tengamos en la carpeta únicamente los ficheros correspondientes al análisis concreto que queramos llevar a cabo. De esta forma, es bastante sencillo configurar el patrón.

Una vez nos hemos hecho con el vector de nombres, simplemente podemos recorrerlo usando un bucle for. Crearemos la ruta hacia cada archivo en particular de manera programática, y luego escribiremos un código general de lectura y extracción de los datos de interés.


for (i in filenames) {
        # Crea la ruta hacia el fichero concreto
        ruta = paste("data/raw/", i, sep="")

        # Lee el archivo
        temp_df = read.table(ruta, 
                             header=TRUE,
                             sep=";",
                             dec=",",
                             stringsAsFactors=FALSE)

        #
        # Hace cosas interesantes con el data frame
        #
}

Si bien es cierto que este tipo de operaciones lo solemos llevar a cabo en R con alguna función de la familia apply(), esta solución, a primera vista, la considero bastante más legible. Dentro de un año, sabrás exactamente en cinco segundos lo que hacía esta porción de código, lo cual no es tan sencillo de conseguir con algunas llamadas a apply() que, normalmente, incluyen la definición de funciones anónimas en su interior.

Un detalle a tener en cuenta en este tipo de códigos es el ámbito (o alcance) de las variables. Aquellas que definamos en el interior del bucle se “perderán” al finalizar éste. Así pues, declararemos, antes de comenzar el bucle, algún tipo de variable que almacene los datos de interés. Por ejemplo, el código para inicializar un data.frame vacío es:


alic = data.frame(Año    = integer(),
                  Mes    = integer(),
                  T.Med. = numeric())

Una vez definido fuera, dentro del bucle podremos actualizar el data.frame haciendo uso de la función rbind().

Recapitulando (y ordenando a la vez la secuencia de acciones propuestas), una posible plantilla para resolver el problema que nos ocupa sería:

# Almacena nombres de archivos
filenames = list.files(path = "data/raw/",
                       pattern = "*.CSV")

# Crea data.frame vacío
alic = data.frame(Año    = integer(),
                  Mes    = integer(),
                  T.Med. = numeric())

# Recorre los ficheros
for (i in filenames) {
        # Crea la ruta hacia el fichero concreto
        ruta = paste("data/raw/", i, sep="")

        # Lee el archivo
        temp_df = read.table(ruta, 
                             header=TRUE,
                             sep=";",
                             dec=",",
                             stringsAsFactors=FALSE)

        #
        # Hace cosas interesantes con el data frame
        #
}

Fuentes:

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s