El tidyverse es una colección de paquetes diseñados para data science y que comparten un modo de trabajo similar.
Figure 1: Página web del tidyverse: https://www.tidyverse.org/
En este recurso aprenderemos el uso de dos comandos del paquete tidyr: pivot_wider y pivot_longer. Para activar los paquetes del tidyverse (incluyendo tidyr) use el siguiente código:
library(tidyverse) # activando paquetes del tidyverse (dplyr, ggplot2, tidyr, etc.)
%>% ó |>)Este operador permite pasar el objeto que esta a su izquierda como primer argumento del comando que está a su derecha, y con esto, favorece la escritura de código donde se deben usar varios comandos, uno detras de otro, para transformar un objeto.
El operador %>% (ó |>) pasa el objeto a su izquierda como primer argumento del comando a su derecha. Es decir, el código:
f(x,y)
es equivalente a
x %>% f(y)
x |> f(y)
Considere las siguientes dos tablas como ejemplos de formatos ancho (izquierda) y largo (derecha):
datw # ANCHO
# A tibble: 6 × 5
id g y1 y2 y3
<int> <chr> <int> <dbl> <dbl>
1 1 b 15 15.9 18.3
2 2 c 5 5.3 6.10
3 3 a 16 17.0 19.5
4 4 a 19 20.1 23.2
5 5 b 12 12.7 14.6
6 6 a 14 14.8 17.1
datl # LARGO
# A tibble: 18 × 4
id g y value
<int> <chr> <chr> <dbl>
1 1 b y1 15
2 1 b y2 15.9
3 1 b y3 18.3
4 2 c y1 5
5 2 c y2 5.3
6 2 c y3 6.10
7 3 a y1 16
8 3 a y2 17.0
9 3 a y3 19.5
10 4 a y1 19
11 4 a y2 20.1
12 4 a y3 23.2
13 5 b y1 12
14 5 b y2 12.7
15 5 b y3 14.6
16 6 a y1 14
17 6 a y2 14.8
18 6 a y3 17.1
Ejemplo 1: Ancho a largo
Considere la siguiente tabla y escribala (a mano) en su cuaderno en formato largo para las columnas m y h
| m | h |
|---|---|
| 3.0 | 10.5 |
| 3.5 | 11.0 |
| 2.0 | 12.0 |
Ejemplo 2: largo a ancho
Considere la siguiente tabla. Escriba (a mano) en su cuaderno una nueva tabla donde separe los valores de z en varias columnas de acuerdo a la columna x:
| i | x | z |
|---|---|---|
| 1 | a | 3.0 |
| 2 | a | 3.5 |
| 1 | b | 2.0 |
| 2 | b | 10.0 |
Son múltiples los escenarios en los cuales necesitamos pasar los datos desde una organización a otra y los comandos pivot_wider y pivot_longer (paquete tidyr) permiten cambiar esta organización desde uno a otro formato. A continuación mostramos el uso de cada comando. Para esto descargue las tablas de ejemplo presentadas arriba y prepare su script de R como sigue:
library(tidyverse) # active el tidyverse
rm(list = ls()) # Borre todo su ambiente de trabajo
# Cargue los datos
load('datwl.RData') # el archivo 'datwl.RData' debe estar en su directorio de trabajo
ls() # imprima los nombres de los objetos cargados
# Imprima las tablas para conocer su contenido
datw # ancho
datl # largo
pivot_widerEste comando recibe los datos en formato largo y los entrega en formato ancho. Cuenta con tres argumentos principales cuyo uso se muestra en seguida:
# Ejemplo de uso del comando pivot_wider ----
pivot_wider(
data = datl, # data.frame en formato largo
# columna desde donde tomaremos los nombres de las nuevas columnas
names_from = 'y',
# columna desde donde tomaremos los valores para llenar las nuevas columnas
values_from = 'value'
)
# A tibble: 6 × 5
id g y1 y2 y3
<int> <chr> <dbl> <dbl> <dbl>
1 1 b 15 15.9 18.3
2 2 c 5 5.3 6.10
3 3 a 16 17.0 19.5
4 4 a 19 20.1 23.2
5 5 b 12 12.7 14.6
6 6 a 14 14.8 17.1
pivot_longerEste comando recibe los datos en formato ancho y los entrega en formato largo. Cuenta con cuatro argumentos principales cuyo uso se muestra en seguida:
# Ejemplo de uso del comando pivot_longer ----
pivot_longer(
data = datw, # datos en formato ancho
# Columnas de data que seran cambiadas a formato largo
cols = y1:y3,
# ¿Como se quiere llamar la nueva columna indicadora?
names_to = 'y',
# ¿Como se quiere llamar la nueva columna que tendra los valores?
values_to = 'value'
)
# A tibble: 18 × 4
id g y value
<int> <chr> <chr> <dbl>
1 1 b y1 15
2 1 b y2 15.9
3 1 b y3 18.3
4 2 c y1 5
5 2 c y2 5.3
6 2 c y3 6.10
7 3 a y1 16
8 3 a y2 17.0
9 3 a y3 19.5
10 4 a y1 19
11 4 a y2 20.1
12 4 a y3 23.2
13 5 b y1 12
14 5 b y2 12.7
15 5 b y3 14.6
16 6 a y1 14
17 6 a y2 14.8
18 6 a y3 17.1
Un aspecto que permite validar, al menos parcialmente, el pivot a formato largo es que el número de filas de la nueva tabla en formato largo debe ser igual al producto de la cantidad de filas de la tabla en formato ancho por el número de variables a “pivotear”. Para el ejemplo de arriba, la tabla en formato ancho tiene 6 filas y se “pivotearon” 3 columnas (y1, y2 y y3), luego, la nueva tabla en formato largo debe tener 6 x 3 = 18 filas totales.
Los datos carData::WeightLoss presentan la perdida de peso y una valoración de autoestima para 34 sujetos en tres tratamientos (Control, Diet y DietEx) durante tres meses.
library(carData)
?WeightLoss # para solicitar ayuda sobre los datos
dat <- WeightLoss
dat <- mutate(WeightLoss, group = factor(group))
str(dat)
'data.frame': 34 obs. of 7 variables:
$ group: Factor w/ 3 levels "Control","Diet",..: 1 1 1 1 1 1 1 1 1 1 ...
$ wl1 : int 4 4 4 3 5 6 6 5 5 3 ...
$ wl2 : int 3 4 3 2 3 5 5 4 4 3 ...
$ wl3 : int 3 3 1 1 2 4 4 1 1 2 ...
$ se1 : int 14 13 17 11 16 17 17 13 14 14 ...
$ se2 : int 13 14 12 11 15 18 16 15 14 15 ...
$ se3 : int 15 17 16 12 14 18 19 15 15 13 ...
Convierta los datos en formato largo “pivoteando” las columnas wl1, wl2 y wl3. La tabla debe quedar como se muestra a continuación:
# A tibble: 102 × 7
id group se1 se2 se3 month wl
<int> <fct> <int> <int> <int> <dbl> <int>
1 1 Control 14 13 15 1 4
2 1 Control 14 13 15 2 3
3 1 Control 14 13 15 3 3
4 2 Control 13 14 17 1 4
5 2 Control 13 14 17 2 4
6 2 Control 13 14 17 3 3
7 3 Control 17 12 16 1 4
8 3 Control 17 12 16 2 3
9 3 Control 17 12 16 3 1
10 4 Control 11 11 12 1 3
# ℹ 92 more rows
Código solución
datl <- dat %>%
mutate(
id = 1:n(),
) %>%
relocate(id, .before = group) %>%
pivot_longer(cols = wl1:wl3, names_to = 'month', values_to = 'wl',
names_prefix = 'wl') %>%
mutate(month = as.numeric(month))
datl
En el contexto de los datos del ejercicio anterior considere que se registraron dos variables respuestas para cada sujeto, la perdida de peso (wl1, wl2 y wl3) pero también un puntaje de autoestima (se1, se2 y se3). Pase los datos a formato largo de tal forma que la nueva tabla se vea como sigue:
# A tibble: 102 × 5
id group month wl se
<int> <fct> <dbl> <int> <int>
1 1 Control 1 4 14
2 1 Control 2 3 13
3 1 Control 3 3 15
4 2 Control 1 4 13
5 2 Control 2 4 14
6 2 Control 3 3 17
7 3 Control 1 4 17
8 3 Control 2 3 12
9 3 Control 3 1 16
10 4 Control 1 3 11
# ℹ 92 more rows
Para lograr esto, considere los siguientes pasos:
Aplique mutate para agregar una nueva columna id con un identificador único para cada sujeto. Utilice relocate para lograr que esta columna id quede de primero.
Aplique pivot_longer para “pivotear” las columnas wl1, wl2, wl3, se1, se2 y se3 a una única columna de valores.
Utilice mutate con el comando substr para separar la columna indicadora en dos nuevas columnas, una que contenga sólo los nombres de las variables (wl y se) y otra que contenga sólo el mes (1, 2 y 3). Remueva la columna indicadora con select.
Aplique pivot_wider para pasar a formato ancho la columna de valores separandola en dos nuevas columnas, una con los valores de wl y otra con los de se.
Código solución
datl2 <- dat %>%
mutate(
id = 1:n(),
) %>%
relocate(id, .before = group) %>%
pivot_longer(cols = wl1:se3, names_to = 'var_month', values_to = 'value') %>%
mutate(
var = substr(var_month, 1,2),
month = as.numeric(substr(var_month, 3,3))
) %>%
select(-var_month) %>%
pivot_wider(
names_from = 'var',
values_from = 'value'
)
datl2
La tabla gestStats presenta algunos estadísticos descriptivos del peso al nacimiento por la edad y por el estatus de fumar de la madre generados desde la base de datos mosaicData::Gestation.
load('gestStats.RData') # el archivo 'gestStats.RData' debe estar en el dir. de trabajo
gestStats # imprima la tabla
# A tibble: 16 × 5
age smoke n stat stat_value
<fct> <chr> <int> <chr> <dbl>
1 15-28 no 460 min 62
2 15-28 no 460 max 176
3 15-28 no 460 mean 123.
4 15-28 no 460 sd 16.1
5 15-28 yes 317 min 65
6 15-28 yes 317 max 163
7 15-28 yes 317 mean 114.
8 15-28 yes 317 sd 17.4
9 28-45 no 281 min 55
10 28-45 no 281 max 174
11 28-45 no 281 mean 123.
12 28-45 no 281 sd 19.4
13 28-45 yes 166 min 58
14 28-45 yes 166 max 160
15 28-45 yes 166 mean 113.
16 28-45 yes 166 sd 19.5
Observe que el valor de los estadísticos se encuentra en una sóla columna lo que dificulta la lectura de la información. Convierta la tabla gestStats a formato ancho de tal forma que la nueva tabla se vea como sigue:
# A tibble: 4 × 7
age smoke n min max mean sd
<fct> <chr> <int> <dbl> <dbl> <dbl> <dbl>
1 15-28 no 460 62 176 123. 16.1
2 15-28 yes 317 65 163 114. 17.4
3 28-45 no 281 55 174 123. 19.4
4 28-45 yes 166 58 160 113. 19.5
Considere las siguientes dos tablas:
d1 <- tibble(
x = c('a', 'a', 'b', 'b'),
z = c(3, 3.5, 2, 10)
)
d1
# A tibble: 4 × 2
x z
<chr> <dbl>
1 a 3
2 a 3.5
3 b 2
4 b 10
d2 <- tibble(
i = c(1,2,1,2),
x = c('a', 'a', 'b', 'b'),
z = c(3, 3.5, 2, 10)
)
d2
# A tibble: 4 × 3
i x z
<dbl> <chr> <dbl>
1 1 a 3
2 2 a 3.5
3 1 b 2
4 2 b 10
Suponga que se quiere “pivotear” la columna z a nuevas columnas de acuerdo a los nombres de la columna x. El comando pivot_wider no funciona desde la tabla d1 pero si desde la tabla d2, observe:
pivot_wider(d1, names_from = x, values_from = z)
Warning: Values from `z` are not uniquely identified; output will contain list-cols.
* Use `values_fn = list` to suppress this warning.
* Use `values_fn = {summary_fun}` to summarise duplicates.
* Use the following dplyr code to identify duplicates.
{data} %>%
dplyr::group_by(x) %>%
dplyr::summarise(n = dplyr::n(), .groups = "drop") %>%
dplyr::filter(n > 1L)
# A tibble: 1 × 2
a b
<list> <list>
1 <dbl [2]> <dbl [2]>
pivot_wider(d2, names_from = x, values_from = z)
# A tibble: 2 × 3
i a b
<dbl> <dbl> <dbl>
1 1 3 2
2 2 3.5 10
Cuando se va a pasar de formato largo a ancho, es importante considerar la columna que indica a los sujetos. Considere estos dos ejemplos similares, pero difieren en que en d1 hay tres filas pero dos sujetos, mientras que en d1 hay tres filas y tres sujetos. Observe que se agregan NA en los espacios perdidos:
d1 <- tibble(
i = c(1,2,1),
x = c('a', 'a', 'b'),
z = c(3, 3.5, 2)
)
d1
# A tibble: 3 × 3
i x z
<dbl> <chr> <dbl>
1 1 a 3
2 2 a 3.5
3 1 b 2
pivot_wider(d1, names_from = x, values_from = z)
# A tibble: 2 × 3
i a b
<dbl> <dbl> <dbl>
1 1 3 2
2 2 3.5 NA
d2 <- tibble(
i = c(1,2,3),
x = c('a', 'a', 'b'),
z = c(3, 3.5, 2)
)
d2
# A tibble: 3 × 3
i x z
<dbl> <chr> <dbl>
1 1 a 3
2 2 a 3.5
3 3 b 2
pivot_wider(d2, names_from = x, values_from = z)
# A tibble: 3 × 3
i a b
<dbl> <dbl> <dbl>
1 1 3 NA
2 2 3.5 NA
3 3 NA 2