Saltar al contenido principal

Long to Wide Data in R

Learn why you would transform your data from a long to a wide format and vice versa and explore how to do this in R with melt() and dcast()!
· 15 min leer

Explora con IA

Hay momentos en los que necesitas convertir datos del formato largo (lo llamaremos «formato long», y enseguida verás a qué nos referimos) al formato ancho y viceversa. En la vida real, los datos llegan en todo tipo de formatos, pero muchas funciones de R están pensadas para un formato concreto.

Por ejemplo, lme4::lmer() para modelos lineales mixtos y ggplot2::ggplot() para visualización están diseñadas para formato long. Otras, como mosaicplot(), funcionan mejor con formato ancho. Eso significa que tendrás que convertir el formato para analizar o visualizar, salvo que tus datos ya estén procesados y en el formato adecuado.

En R hay varias opciones para convertir formatos, pero al empezar puede resultar algo confuso.

En este tutorial vas a entender la mecánica de convertir datos entre formato long y ancho. Verás estas ideas:

  • Aprenderás qué es el formato long.
  • Después, verás el formato ancho.
  • Repasarás las diferencias entre ambos;
  • Y qué pasos seguir para pasar de un formato a otro.
  • Por último, lo pondrás en práctica en R. Verás cómo pasar de formato long a formato ancho con las funciones melt() y dcast().

Los datos

Tabla 01
namegenderyear2011year2012year2013year2014year2015
Jackson SmithM74.6984.9991.73105.11111.04
Sophia JohnsonFNANANANA75.89
Emma WilliamsFNANA75.7486.5091.50
Aiden JonesMNANANA71.8981.42
Liam BrownM88.2496.91101.85108.13112.45
Lucas DavisM70.6083.7894.17100.03106.35
Olivia MillerF64.7880.7687.3097.13103.80
Ava WilsonF88.7796.45104.72112.84NA

Esta tabla muestra la estatura de bebés en una zona local. Las mediciones van de 2011 a 2015. Como sabrás, NA significa «no disponible». Por la posición de los NA puedes deducir la edad de los bebés, pero la edad exacta no aparece. Aunque la tabla parece ordenada, para estudiar el crecimiento hay un problema: lo relevante no es el momento absoluto de la medición, sino la edad que tenía el bebé al medirse. ¿Podrías añadir esa información a la tabla? Aquí tienes una forma:

Tabla 02
namegenderage0age1age2age3age4age5age6
Jackson SmithMNA76.6984.9197.06105.73107.32NA
Sophia JohnsonFNA76.05NANANANANA
Emma WilliamsF72.6582.4691.76NANANANA
Aiden JonesM69.7679.89NANANANANA
Liam BrownMNANA85.3493.22105.78105.84114.82
Lucas DavisM71.5984.8792.10100.73104.21NANA
Olivia MillerF62.7481.3992.0298.32106.44NANA
Ava WilsonFNANA88.39100.67107.58111.52NA

Ha aumentado el número de NA. ## Datos en formato ancho Pero ¿qué harías si quisieras indicar cuántos meses tenía el bebé? Podría verse así:

Tabla 03
namegenderm4m6m7m10m12...m55m60m65m72
Jackson SmithMNANANANA76.69...NA107.32NANA
Sophia JohnsonFNANANANA76.05...NANANANA
Emma WilliamsFNANANA72.65NA...NANANANA
Aiden JonesMNA69.76NANANA...NANANANA
Liam BrownMNANANANANA...NA105.84NA114.82
Lucas DavisMNANA71.59NANA...104.21NANANA
Olivia MillerF62.74NANANANA...NANANANA
Ava WilsonFNANANANANA...NANA111.52NA

Como ves, hay muchísimos NA. Si las edades relativas difieren, el formato ancho desperdicia mucho espacio. Otra opción sería indicar las edades que tenían en 2015, pero solo funciona si todos se midieron en el mismo momento absoluto. Si difieren por meses y quieres saber la edad en meses, no sirve. En ese caso, este ejemplo parece la única forma. Aquí te conviene usar el formato long. ## Datos en formato long Mientras que en el formato ancho todas las mediciones de un bebé están en una sola fila, en el formato long cada fila contiene una única medición de un bebé. La forma más simple es poner en una fila el nombre, el momento de medida y el valor (altura). Eso es lo que ves aquí:

Tabla 04
namegendermonthheight
Olivia MillerF462.74
Aiden JonesM669.76
Lucas DavisM771.59
Emma WilliamsF1072.65
Jackson SmithM1276.69
............
Liam BrownM72114.82

Si ordenas por nombre, obtendrás algo como la tabla siguiente. Claramente ocupa menos espacio que la Tabla 3 de arriba.

Tabla 05
namegendermonthheight
Jackson SmithM1276.69
Jackson SmithM2484.91
Jackson SmithM3697.06
Jackson SmithM48105.73
Jackson SmithM60107.32
Sophia JohnsonF1276.05
Emma WilliamsF1072.65
............
Ava WilsonF65111.52

Formato long frente a ancho

Recuerda las diferencias fundamentales entre formato ancho y long: una diferencia simple es que el formato ancho muestra muchas mediciones de un individuo en una sola fila y los nombres de columna indican qué mide cada una.

Esta tabla muestra las alturas de Liam Brown entre 2011 y 2015 en una sola fila:

Tabla 06
namegenderyear2011year2012year2013year2014year2015
Liam BrownM88.2496.91101.85108.13112.45

En formato long, las alturas de Liam Brown aparecen en una sola columna:

Tabla 07
namegender_
Liam BrownM85.34
Liam BrownM93.22
Liam BrownM105.78
Liam BrownM105.84
Liam BrownM114.82

Como ves, no puedes saber a qué corresponde cada medición. Si incluyes el nombre de la columna, quedaría así:

Tabla 08
namegenderyear2011, 2012, 2013, 2014, 2015
Liam BrownM85.34
Liam BrownM93.22
Liam BrownM105.78
Liam BrownM105.84
Liam BrownM114.82

Pero esto tiene su propio problema. A Sophia Johnson no se le midió la altura en 2011-2014. Así que, como ves, el nombre de la columna no se puede fijar fácilmente:

Tabla 09
namegender?
Liam BrownM85.34
Liam BrownM93.22
Liam BrownM105.78
Liam BrownM105.84
Liam BrownM114.82
Sophia JohnsonF76.05

De formato ancho a formato long

Convertir de ancho a long puede verse como un proceso por pasos. Antes de pasar todas las mediciones de una fila a una columna, puedes crear una tabla con una sola medición por fila. Hagámoslo con esta tabla:

Tabla 10
namegenderage0age1age2age3age4age5age6
Emma WilliamsF72.6582.4691.76NANANANA
Aiden JonesM69.7679.89NANANANANA

El resultado sería como esta tabla:

Tabla 11
namegenderage0age1age2age3age4age5age6
Emma WilliamsF72.65  NANANANA
Emma WilliamsF 82.46    NA
Emma WilliamsF  91.76    
Aiden JonesM69.76 NANANANANA
Aiden JonesM 79.89     

Antes de reunir en una sola columna esas mediciones dispersas, necesitas una columna adicional que indique qué medición es, como aquí:

Tabla 12
namegendermeasureage0age1age2age3age4age5age6
Emma WilliamsFage072.65  NANANANA
Emma WilliamsFage1 82.46    NA
Emma WilliamsFage2  91.76    
Aiden JonesMage069.76 NANANANANA
Aiden JonesMage1 79.89     

El nombre de esa columna suele ser "measure" o "key". Fíjate que aparecen "age0", "age1", "age2", "age3", "age4", "age5" tanto como nombres de columna como en una columna. Si omites los nombres de columna, la tabla queda así:

Tabla 13
namegendermeasure____________________________
Emma WilliamsFage072.65  NANANANA
Emma WilliamsFage1 82.46     
Emma WilliamsFage2  91.76    
Aiden JonesMage069.76 NANANANANA
Aiden JonesMage1 79.89     

Como ahora hay una sola medición por fila, ya puedes reunirlas en una única columna. El resultado sería:

Tabla 14
namegendermeasure 
Emma WilliamsFage072.65
Emma WilliamsFage182.46
Emma WilliamsFage291.76
Aiden JonesMage069.76
Aiden JonesMage179.89

Vamos a darle un nombre a esa nueva columna de valores. Normalmente se llama «value»:

Tabla 15
namegendermeasurevalue
Emma WilliamsFage072.65
Emma WilliamsFage182.46
Emma WilliamsFage291.76
Aiden JonesMage069.76
Aiden JonesMage179.89

Mira la tabla anterior. ¿Ves que «age» se repite? Puedes eliminar esa parte repetida y quedarte con:

Tabla 16
namegenderagevalue
Emma WilliamsF072.65
Emma WilliamsF182.46
Emma WilliamsF291.76
Aiden JonesM069.76
Aiden JonesM179.89

Age, que se repetía en cada fila, ahora es el nombre de una columna. Y value puede ser más específico: cámbialo por height, que es más informativo. El resultado:

Tabla 17
namegenderageheight
Emma WilliamsF072.65
Emma WilliamsF182.46
Emma WilliamsF291.76
Aiden JonesM069.76
Aiden JonesM179.89

Compáralas: en la Tabla 15, value podría significar cualquier cosa; en la Tabla 17, height es específico: solo puede ser altura. Otra opción sería esta:

Tabla 18
namegendermeasurevalue
Emma WilliamsFheight.age072.65
Emma WilliamsFheight.age182.46
Emma WilliamsFheight.age291.76
Aiden JonesMheight.age069.76
Aiden JonesMheight.age179.89

Piensa ahora que las mediciones son diversas. Si tienes altura, peso y el IMC, quedaría como la siguiente tabla. Pero en este caso, value mezcla magnitudes en escalas distintas y puede confundir. Aquí la altura está en centímetros y el peso en kilogramos:

Tabla 19
namegendermeasurevalue
Emma WilliamsFheight72.65
Emma WilliamsFweight8.22
Emma WilliamsFBMI22.60
Aiden JonesMheight69.76
Aiden JonesMweight8.51

Así que, al convertir de ancho a long, debes decidir qué valores reunirás en una sola columna. Después eliges el nombre de esa columna.

Resumamos: para convertir de ancho a long debes decidir qué columnas combinar en una sola. Al hacerlo, muchas columnas se condensan en una. Necesitas un nombre para esa nueva columna, como verás en las tablas siguientes:

Tabla 20
id1id2age0age1age2
Emma WilliamsFNA82.4691.76
Aiden JonesM69.7679.89NA
Emma WilliamsFNA82.4691.76
Tabla 21
id1id2age0age1age2
Emma WilliamsFNA  
Emma WilliamsF 82.46 
Emma WilliamsF  91.76
Aiden JonesM69.76  
Aiden JonesM 79.89 
Aiden JonesM  NA
Emma WilliamsFNA  
Emma WilliamsF 82.46 
Emma WilliamsF  91.76
Tabla 22
id1id2age_age0age1age2
Emma WilliamsFage0NA  
Emma WilliamsFage1 82.46 
Emma WilliamsFage2  91.76
Aiden JonesMage069.76  
Aiden JonesMage1 79.89 
Aiden JonesMage2  NA
Emma WilliamsFage0NA  
Emma WilliamsFage1 82.46 
Emma WilliamsFage2  91.76
Tabla 23
id1id2age_ 
Emma WilliamsFage0NA
Emma WilliamsFage182.46
Emma WilliamsFage291.76
Aiden JonesMage069.76
Aiden JonesMage179.89
Aiden JonesMage2NA
Emma WilliamsFage0NA
Emma WilliamsFage182.46
Emma WilliamsFage291.76
Tabla 24
id1id2keyvalue
Emma WilliamsFage0NA
Emma WilliamsFage182.46
Emma WilliamsFage291.76
Aiden JonesMage069.76
Aiden JonesMage179.89
Aiden JonesMage2NA
Emma WilliamsFage0NA
Emma WilliamsFage182.46
Emma WilliamsFage291.76
Tabla 25
id1id2keyvalue
Emma WilliamsFage182.46
Emma WilliamsFage291.76
Aiden JonesMage069.76
Aiden JonesMage179.89
Emma WilliamsFage182.46
Emma WilliamsFage291.76

Fíjate en las columnas id1 e id2. id2 no identifica a una persona, sino que es un atributo (gender). Es decir, también es una medición. Así que puedes llevarla al formato aún más long. El formato «más largo» tiene tres columnas: id, key y value.

Tabla 26
idkeyvalue
Emma WilliamsgenderF
Emma Williamsage182.46
Emma Williamsage291.76
Aiden JonesgenderF
Aiden Jonesage069.76
Aiden Jonesage179.89
Emma WilliamsgenderF
Emma Williamsage182.46
Emma Williamsage291.76

La tabla anterior muestra el formato más long a partir de la tabla 25. Pero diferentes personas pueden compartir nombre.

En ese caso, el formato long puede ser confuso porque id no identifica de forma única. Puedes añadir un número al nombre para distinguir (por ejemplo, con make.unique() de R), pero no puedes diferenciar entre un nombre original y uno que ya llevaba un número. ¡Imagina a alguien que realmente se llame «John.2»!

La salida obvia es asignar un identificador numérico distinto a cada persona. En ese caso, los nombres pasan a ser otra medición.

La siguiente tabla trata incluso los nombres como mediciones. En cierto modo, es el formato verdaderamente más long.

Tabla 27
idkeyvalue
1nameEmma Williams
1genderF
1age182.46
1age291.76
2nameAiden Jones
2genderF
2age069.76
2age179.89
3nameEmma Williams
3genderF
3age182.46
3age291.76

El formato más long es el más sencillo para volver al formato ancho. Si inviertes el proceso de las Tablas 20 a 25, llegas al formato ancho. Aquí se muestra el proceso:

Tabla 28. Las mediciones en la columna key pasan a los nombres de columna
idkeynamegenderage0age1age2
1nameEmma Williams    
1gender F   
1age1   82.46 
1age2    91.76
2nameAiden Jones    
2gender F   
2age0  69.76  
2age1   79.89 
3nameEmma Williams    
3gender F   
3age1   82.46 
3age2    91.76
Tabla 29. Se puede eliminar la columna key
idnamegenderage0age1age2
1Emma Williams    
1 F   
1   82.46 
1    91.76
2Aiden Jones    
2 F   
2  69.76  
2   79.89 
3Emma Williams    
3 F   
3   82.46 
3    91.76
Tabla 30. Reúne en una fila los registros con el mismo id
idnamegenderage0age1age2
1Emma WilliamsF 82.4691.76
1     
1     
1     
2Aiden JonesF69.7679.89 
2     
2     
2     
3Emma WilliamsF 82.4691.76
3     
3     
3     
Tabla 31. Elimina las filas sin mediciones
idnamegenderage0age1age2
1Emma WilliamsF 82.4691.76
2Aiden JonesF69.7679.89 
3Emma WilliamsF 82.4691.76

La clave al convertir de ancho a long es decidir qué columnas se reunirán en una sola.

Pero no tiene por qué ser solo una. Puedes usar dos columnas si lo necesitas, como en la tabla siguiente:

Tabla 32
namegenderh2011h2012w2011w2012
Jackson SmithM74.6984.999.6012.0
Olivia MillerFNA80.767.1510.7
Ava WilsonF88.7796.45NA15.0

¿Puedes pasarlo a formato long?

Las columnas h2011, h2012, w2011, w2012 representan altura y peso en 2011 y 2012. height y weight están en escalas distintas (cm, kg). Puedes reunir ambas en una sola columna o usar dos columnas, como aquí:

Tabla 33
namegenderyearheightweight
Jackson SmithM201174.699.60
Jackson SmithM201284.9912.00
Olivia MillerF2011NA80.76
Olivia MillerF20127.1510.70
Ava WilsonF201188.7796.45
Ava WilsonF2012NA15.00

¿Esto es formato long o ancho?

De long a ancho en R

Vamos a hacer la conversión entre formatos long y ancho en R. Hay muchas funciones y paquetes para ello.

Tabla 34
funcpackageto_long_formto_wide_form
stack/unstackutilsstackunstack
reshapestatsreshape(direction="long", ...)reshape(direction="wide", ...)
melt/dcastreshape2meltdcast
gather/spreadtidyrgatherspread

Aquí explicaremos cómo usar melt() y dcast() del paquete reshape2. ¿Por qué? Porque stack() y unstack() son funciones básicas y suelen requerir posprocesado. Ten en cuenta que gather() y spread() de tidyr también son muy populares, pero no las cubriremos en este tutorial.

Otra función que puedes usar es reshape(), del paquete stats. Ojo, no la confundas con el paquete reshape. Este paquete, junto con reshape2, se creó precisamente para quienes tenían dificultades con reshape(). Además, reshape() parece asumir datos longitudinales (mediciones repetidas en el tiempo).

Convirtamos los datos de la tabla 35 al formato long. Supón que la tabla siguiente está en un data.frame llamado dat.

Tabla 35
namegenderyear2011year2012year2013
Jackson SmithM74.6984.9991.73
Emma WilliamsFNANA75.74
Liam BrownM88.24NA101.85
Ava WilsonF88.7796.45NA

babies = data.frame(name= c("Jackson Smith", "Emma Williams", "Liam Brown", "Ava Wilson"), gender = c("M", "F", "M", "F"), year2011= c(74.69, NA, 88.24, 88.77), year2012=c(84.99, NA, NA, 96.45), year2013=c(91.73, 75.74, 101.83, NA)) babies

##            name gender year2011 year2012 year2013
## 1 Jackson Smith      M    74.69    84.99    91.73
## 2 Emma Williams      F       NA       NA    75.74
## 3    Liam Brown      M    88.24       NA   101.83
## 4    Ava Wilson      F    88.77    96.45       NA

La pregunta que debes hacerte es: «¿qué columnas voy a combinar en una sola?».

Serían year2011, year2012, year2013. Al usar melt(), esas columnas van en measure.vars:

melt(babies, measure.vars = c("year2011", "year2012", "year2013"))

##             name gender variable  value
## 1  Jackson Smith      M year2011  74.69
## 2  Emma Williams      F year2011     NA
## 3     Liam Brown      M year2011  88.24
## 4     Ava Wilson      F year2011  88.77
## 5  Jackson Smith      M year2012  84.99
## 6  Emma Williams      F year2012     NA
## 7     Liam Brown      M year2012     NA
## 8     Ava Wilson      F year2012  96.45
## 9  Jackson Smith      M year2013  91.73
## 10 Emma Williams      F year2013  75.74
## 11    Liam Brown      M year2013 101.83
## 12    Ava Wilson      F year2013     NA

year2011, year2012, year2013 están en las columnas 3, 4 y 5, así que también puedes indicar eso:

melt(babies, measure.vars = 3:5)

##             name gender variable  value
## 1  Jackson Smith      M year2011  74.69
## 2  Emma Williams      F year2011     NA
## 3     Liam Brown      M year2011  88.24
## 4     Ava Wilson      F year2011  88.77
## 5  Jackson Smith      M year2012  84.99
## 6  Emma Williams      F year2012     NA
## 7     Liam Brown      M year2012     NA
## 8     Ava Wilson      F year2012  96.45
## 9  Jackson Smith      M year2013  91.73
## 10 Emma Williams      F year2013  75.74
## 11    Liam Brown      M year2013 101.83
## 12    Ava Wilson      F year2013     NA

El resultado es la tabla de arriba. Fíjate en los nombres de columna variable y value. Las tablas 23 y 24 mostraron que se necesitan nuevos nombres. melt() usa esos por defecto, pero puedes cambiarlos con variable.name= y value.name=. Hagámoslo:

melt(babies, measure.vars=3:5, variable.name="year", value.name="height")

##             name gender     year height
## 1  Jackson Smith      M year2011  74.69
## 2  Emma Williams      F year2011     NA
## 3     Liam Brown      M year2011  88.24
## 4     Ava Wilson      F year2011  88.77
## 5  Jackson Smith      M year2012  84.99
## 6  Emma Williams      F year2012     NA
## 7     Liam Brown      M year2012     NA
## 8     Ava Wilson      F year2012  96.45
## 9  Jackson Smith      M year2013  91.73
## 10 Emma Williams      F year2013  75.74
## 11    Liam Brown      M year2013 101.83
## 12    Ava Wilson      F year2013     NA

Las mediciones se especificaron arriba. En estos casos, Id puede especificar indirectamente las mediciones. Así que puedes elegir columnas para id en lugar de para mediciones.

Los resultados son iguales en ambos casos. El primero elige columnas para id, el segundo elige columnas para reunir:

melt(babies, id.vars=c("name","gender"))

melt(babies, measure.vars = c("year2011", "year2012", "year2013"))

##             name gender variable  value
## 1  Jackson Smith      M year2011  74.69
## 2  Emma Williams      F year2011     NA
## 3     Liam Brown      M year2011  88.24
## 4     Ava Wilson      F year2011  88.77
## 5  Jackson Smith      M year2012  84.99
## 6  Emma Williams      F year2012     NA
## 7     Liam Brown      M year2012     NA
## 8     Ava Wilson      F year2012  96.45
## 9  Jackson Smith      M year2013  91.73
## 10 Emma Williams      F year2013  75.74
## 11    Liam Brown      M year2013 101.83
## 12    Ava Wilson      F year2013     NA

Si especificas tanto id.vars como measure.vars, las columnas no incluidas en ninguna se excluyen del resultado. Mira el siguiente bloque de código:

melt(babies, id.vars=c("name"), measure.vars=c("year2011", "year2012"))

##            name variable value
## 1 Jackson Smith year2011 74.69
## 2 Emma Williams year2011    NA
## 3    Liam Brown year2011 88.24
## 4    Ava Wilson year2011 88.77
## 5 Jackson Smith year2012 84.99
## 6 Emma Williams year2012    NA
## 7    Liam Brown year2012    NA
## 8    Ava Wilson year2012 96.45

Además, na.rm=T puede eliminar los NA:

melt(babies, id.vars=c("name"), measure.vars=c("year2011", "year2012"), na.rm=T)

##            name variable value
## 1 Jackson Smith year2011 74.69
## 3    Liam Brown year2011 88.24
## 4    Ava Wilson year2011 88.77
## 5 Jackson Smith year2012 84.99
## 8    Ava Wilson year2012 96.45

La función dcast() hace lo inverso a melt(). id, variable y value son las columnas del formato más long. dcast(data, id ~ variable, value.var="value") lleva el formato más long al formato ancho.

babiesLong <- melt(babies, id.vars=c("name"), measure.vars=c("year2011", "year2012"), na.rm=T)
babiesLong

##            name variable value
## 1 Jackson Smith year2011 74.69
## 3    Liam Brown year2011 88.24
## 4    Ava Wilson year2011 88.77
## 5 Jackson Smith year2012 84.99
## 8    Ava Wilson year2012 96.45

babiesLong tiene name para id, variable para variable y value para value. Así que puedes usar dcast() para pasarlo a formato long:

dcast(babiesLong, name ~ variable, value.var="value")

##            name year2011 year2012
## 1    Ava Wilson    88.77    96.45
## 2 Jackson Smith    74.69    84.99
## 3    Liam Brown    88.24       NA

Conclusión

Eso es todo. En este tutorial te has centrado en entender la lógica y el proceso de reestructuración de datos. Normalmente, el formato long es preferible para el análisis, pero hay excepciones. La presentación de datos en formato ancho puede ahorrar espacio cuando es apropiado, pero a medida que aumenta el número de valores faltantes, es mejor convertir al formato long.

Para la conversión de formato, debes centrarte en cuáles son las mediciones. El lema del formato long es una medición por fila, y el formato ancho tiene muchas mediciones en una fila. Cuando haces que las mediciones a lo largo de las columnas se reúnan en una sola, los nombres de columna originales deben conservarse en una columna adicional. Cuando haces que las mediciones en una columna se dispersen a lo largo de las columnas, debes averiguar cuáles deberían ser los nombres de columna a partir de la columna variable.

Una vez que entiendes el proceso, usar funciones como dcast() y melt() resulta mucho más fácil.

Temas

Relacionado

Tutorial

Tutorial de regresión lineal en R