8.1 La función melt y datos en formato largo

Una tabla está en formato largo cuando cada fila contiene un dato y el resto de las columnas son etiquetas que le dan contexto. Además de ser más claras conceptualmente, suele ser más sencillo procesar tablas en formato largo. A los interesados en saber más sobre este tipo de datos se les recomienda leer el artículo Tidy Data29.

Vamos a comenzar leyendo un fichero de datos que contiene la población en 2014 de las provincias aragonesas por sexo. Se trata de un conjunto de datos simple y minúsculo pero que, gracias a eso, permite visualizar las transformaciones que vamos a realizar.

pob.aragon.2014 <- read.table("data/pob_aragon_2014.csv", 
                              header = T, sep = "\t")
pob.aragon.2014
##   Provincia Hombres Mujeres
## 1    Huesca  113840  111069
## 2    Teruel   71449   68916
## 3  Zaragoza  471675  488436

Es habitual encontrar conjuntos de datos (aunque típicamente más grandes) en formatos similares. Estos datos no están en formato largo o arreglado. En tablas arregladas, las columnas representan necesariamente variables. Sin embargo, en pob.aragon.2014 existe una variable implícita, sexo de la que Hombres y Mujeres son niveles (o valores).

Podemos usar la función melt para pivotar la tabla y arreglar los datos, i.e., disponerlos en formato largo:

library(reshape2)
melt(pob.aragon.2014)   
##   Provincia variable  value
## 1    Huesca  Hombres 113840
## 2    Teruel  Hombres  71449
## 3  Zaragoza  Hombres 471675
## 4    Huesca  Mujeres 111069
## 5    Teruel  Mujeres  68916
## 6  Zaragoza  Mujeres 488436

Es evidente que la información contenida en ambos conjuntos de datos es la misma. Pero en la nueva tabla cada fila tiene un único valor. El resto de las columnas, Provincia y variable —como R desconoce que el nombre ideal de la nueva variable sería sexo, por defecto, la denomina variable— contextualizan dicha cifra.

Un ejemplo un poco más intersante es este:

pob.aragon <- read.table("data/pob_aragon.csv", 
                         header = T, sep = "\t")
pob.aragon
##   Provincia Periodo Hombres Mujeres
## 1    Huesca    2014  113840  111069
## 2    Huesca    2004  107961  104940
## 3    Teruel    2014   71449   68916
## 4    Teruel    2004   71073   68260
## 5  Zaragoza    2014  471675  488436
## 6  Zaragoza    2004  441840  455510

El nuevo conjunto de datos tiene una variable adicional, Periodo. Si se le aplica melt directamente, el resultado dista del esperado:

melt(pob.aragon)
##    Provincia variable  value
## 1     Huesca  Periodo   2014
## 2     Huesca  Periodo   2004
## 3     Teruel  Periodo   2014
## 4     Teruel  Periodo   2004
## 5   Zaragoza  Periodo   2014
## 6   Zaragoza  Periodo   2004
## 7     Huesca  Hombres 113840
## 8     Huesca  Hombres 107961
## 9     Teruel  Hombres  71449
## 10    Teruel  Hombres  71073
## 11  Zaragoza  Hombres 471675
## 12  Zaragoza  Hombres 441840
## 13    Huesca  Mujeres 111069
## 14    Huesca  Mujeres 104940
## 15    Teruel  Mujeres  68916
## 16    Teruel  Mujeres  68260
## 17  Zaragoza  Mujeres 488436
## 18  Zaragoza  Mujeres 455510

Efectivamente, R confunde Periodo con un nivel más de la nueva variable, junto a Hombres y Mujeres. Pero, en realidad, tanto la provincia como el periodo forman la clave de la tabla. Esto se le puede indicar a melt así:

melt(pob.aragon, id.vars = c("Provincia", "Periodo"))
##    Provincia Periodo variable  value
## 1     Huesca    2014  Hombres 113840
## 2     Huesca    2004  Hombres 107961
## 3     Teruel    2014  Hombres  71449
## 4     Teruel    2004  Hombres  71073
## 5   Zaragoza    2014  Hombres 471675
## 6   Zaragoza    2004  Hombres 441840
## 7     Huesca    2014  Mujeres 111069
## 8     Huesca    2004  Mujeres 104940
## 9     Teruel    2014  Mujeres  68916
## 10    Teruel    2004  Mujeres  68260
## 11  Zaragoza    2014  Mujeres 488436
## 12  Zaragoza    2004  Mujeres 455510

Los datos en formato largo están muy relacionados con los arrays (conocidos en algunos contextos empresariales como cubos multidimensionales). Un ejemplo de ellos es la tabla Titanic de R, que se refiere a los viajeros del Titanic, y que tiene cuatro dimensiones: la clase, el sexo, el grupo de edad y si sobrevivieron o no al hundimiento:

dimnames(Titanic)
## $Class
## [1] "1st"  "2nd"  "3rd"  "Crew"
## 
## $Sex
## [1] "Male"   "Female"
## 
## $Age
## [1] "Child" "Adult"
## 
## $Survived
## [1] "No"  "Yes"

La función as.data.frame aplicada a un array multidimensional produce una tabla en formato largo:

tmp <- as.data.frame(Titanic)
rbind(head(tmp), tail(tmp))
##    Class    Sex   Age Survived Freq
## 1    1st   Male Child       No    0
## 2    2nd   Male Child       No    0
## 3    3rd   Male Child       No   35
## 4   Crew   Male Child       No    0
## 5    1st Female Child       No    0
## 6    2nd Female Child       No    0
## 27   3rd   Male Adult      Yes   75
## 28  Crew   Male Adult      Yes  192
## 29   1st Female Adult      Yes  140
## 30   2nd Female Adult      Yes   80
## 31   3rd Female Adult      Yes   76
## 32  Crew Female Adult      Yes   20

La función melt también funciona con matrices. Una de ellas es VADeaths. Usa melt para disponer esa matriz en formato largo. Verás que aparece una columna con valores del tipo Rural Male: construye a partir de ella dos columnas (sex y residency). Nota: existe una función auxiliar en reshape2, colsplit que realiza precisamente esa operación.

Toma el conjunto de datos airquality y disponlo en formato largo. Ten cuidado con la definición de la clave de la tabla.

Cambia el nombre a la variable variable creada automáticamente por melt en el ejercicio anterior.

Calcula el valor mediano (median) de las variables de airquality (después de haberlo dispuesto en formato largo). Usa la función tapply.

En general, disponer datos en formato largo facilita muchas operaciones de manipulación de datos. En el ejercicio anterior, en lugar de calcular la mediana variable a variable, ha sido posible obtenerla en dos líneas de código. Que son independientes, además, del número de indicadores de la tabla.


  1. Cuyo autor lo es también del paquete reshape2, el tema de esta sección