Para comenzar, cargaremos algunos paquetes necesarios.
library(tidyverse) # Basta con 'tidyr', 'dplyr', 'readr'
## -- Attaching packages ---------------------------------------------------------------------- tidyverse 1.3.0 --
## v ggplot2 3.3.1 v purrr 0.3.4
## v tibble 3.0.1 v dplyr 1.0.0
## v tidyr 1.1.0 v stringr 1.4.0
## v readr 1.3.1 v forcats 0.5.0
## -- Conflicts ------------------------------------------------------------------------- tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
pivot_longer() se necesita comúnmente para ordenar los conjuntos de datos capturados en crudo, ya que a menudo se optimizan para facilitar la entrada de datos o la facilidad de comparación en lugar de la facilidad de análisis. El conjunto de datos relig_income almacena recuentos basados en una encuesta que (entre otras cosas) preguntó a las personas sobre su religión e ingresos anuales:
relig_income
Este conjunto de datos contiene tres variables: 1) religion, almacenada en las filas; 2) income repartidos entre los nombres de columna; y 3) count almacenado en los valores de las celdas. Para ordenarlo usamos pivot_longer():
relig_income %>%
pivot_longer(-religion,
names_to = "income",
values_to = "count")
El conjunto de datos billboard registra el rango de la cartelera de canciones en el año 2000. Tiene una forma similar a los datos relig_income, pero los datos codificados en los nombres de columna son realmente un número, no una cadena.
billboard
Podemos comenzar con la misma especificación básica que para el conjunto de datos relig_income. Aquí queremos que los nombres se conviertan en una variable llamada week, y los valores se conviertan en una variable llamada rank. También uso values_drop_na para soltar filas que corresponden a valores faltantes. No todas las canciones permanecen en las listas durante las 76 semanas, por lo que la estructura de los datos de entrada obliga a la creación de NA explícitos e inútiles.
billboard %>%
pivot_longer(
cols = starts_with("wk"),
names_to = "week",
values_to = "rank",
values_drop_na = TRUE
)
Sería bueno determinar fácilmente cuánto tiempo permaneció cada canción en las listas, pero para hacer eso, necesitaremos convertir la variable week en un número entero. Podemos hacerlo usando dos argumentos adicionales: names_prefix elimina el prefijo wk, y names_ptypes especifica que la semana debe ser un número entero:
billboard %>%
pivot_longer(
cols = starts_with("wk"),
names_to = "week",
names_prefix = "wk",
values_to = "rank",
values_drop_na = TRUE,
)
Una situación más desafiante ocurre cuando hay múltiples variables agrupadas en los nombres de las columnas. Por ejemplo, tome el conjunto de datos who:
who
country, iso2, iso3 y year ya son variables, por lo que pueden dejarse como están. Pero las columnas de new_sp_m014 a newrel_f65 codifican cuatro variables en sus nombres: El prefijo new_ / new indica que estos son recuentos de casos nuevos. Este conjunto de datos solo contiene casos nuevos, por lo que lo ignoraremos aquí porque es constante. sp / rel / sp / ep describe cómo se diagnosticó el caso. m / f da el género. 014/1524/2535/3544/4554/65 suministra el rango de edad. Podemos dividir estas variables especificando múltiples nombres de columna en names_to, y luego proporcionando names_sep o names_pattern. Aquí names_pattern es el ajuste más natural. Tiene una interfaz similar para extraer: le da una expresión regular que contiene grupos (definida por ()) y coloca cada grupo en una columna.
who %>% pivot_longer(
cols = new_sp_m014:newrel_f65,
names_to = c("diagnosis", "gender", "age"),
names_pattern = "new_?(.*)_(.)(.*)",
values_to = "count"
)
Podríamos ir un paso más allá y especificar los tipos de las columnas de gender y age. Creo que esta es una buena práctica cuando tienes variables categóricas con un conjunto conocido de valores.
who %>% pivot_longer(
cols = new_sp_m014:newrel_f65,
names_to = c("diagnosis", "gender", "age"),
names_pattern = "new_?(.*)_(.)(.*)",
names_ptypes = list(
gender = factor(levels = c("f", "m")),
age = factor(
levels = c("014", "1524", "2534", "3544", "4554", "5564", "65"),
ordered = TRUE
)
),
values_to = "count",
)
Hasta ahora, hemos estado trabajando con marcos de datos que tienen una observación por fila, pero muchos problemas importantes al pivotar implican múltiples observaciones por fila. Por lo general, puede reconocer este caso porque el nombre de la columna que desea que aparezca en la salida es parte del nombre de la columna en la entrada.
family <- tribble(
~family, ~dob_child1, ~dob_child2, ~gender_child1, ~gender_child2,
1L, "1998-11-26", "2000-01-29", 1L, 2L,
2L, "1996-06-22", NA, 2L, NA,
3L, "2002-07-11", "2004-04-05", 2L, 2L,
4L, "2004-10-10", "2009-08-27", 1L, 1L,
5L, "2000-12-05", "2005-02-28", 2L, 1L,
)
family <- family %>% mutate_at(vars(starts_with("dob")), parse_date)
family
Tenga en cuenta que tenemos dos piezas de información (o valores) para cada niño: gender y dob (date of birth). Estos deben ir en columnas separadas en el resultado. Nuevamente suministramos múltiples variables a names_to, usando names_sep para dividir cada nombre de variable. Tenga en cuenta el nombre especial .value: esto le dice a pivot_longer() que esa parte del nombre de la columna especifica el valor que se está midiendo (que se convertirá en una variable en la salida).
family %>%
pivot_longer(
-family,
names_to = c(".value", "child"),
names_sep = "_",
values_drop_na = TRUE
)
Tenga en cuenta el uso de values_drop_na = TRUE: la forma de entrada fuerza la creación de variables explícitas que faltan para las observaciones que no existen.
Ocasionalmente se encontrará con conjuntos de datos que tienen nombres de columna duplicados. En general, es difícil trabajar con dichos conjuntos de datos en R, porque cuando hace referencia a una columna por su nombre, solo encuentra la primera coincidencia. Para crear un tibble con nombres duplicados, debe optar explícitamente por la reparación de nombres que generalmente le impide crear dicho conjunto de datos:
df <- tibble(x = 1:3, y = 4:6, y = 5:7, y = 7:9, .name_repair = "minimal")
df
Cuando pivot_longer() encuentra dichos datos, agrega automáticamente otra columna a la salida:
df %>% pivot_longer(-x, names_to = "name", values_to = "value")
pivot_wider() es lo opuesto a pivot_longer(): amplía un conjunto de datos al aumentar el número de columnas y disminuir el número de filas. Es relativamente raro necesitar pivot_wider() para hacer datos ordenados, pero a menudo es útil para crear tablas de resumen para la presentación, o datos en un formato que necesitan otras herramientas. O para ordenar datos recuperados usando SQL.
Captura-recaptura de datos
El conjunto de datos fish_encounters, aportado por Myfanwy Johnston, describe cuándo los peces que nadan río abajo son detectados por estaciones de monitoreo automático:
fish_encounters
Muchas herramientas utilizadas para analizar estos datos lo necesitan en una forma donde cada estación es una columna:
fish_encounters %>% pivot_wider(names_from = station, values_from = seen)
Este conjunto de datos solo registra cuando la estación detectó un pez; no registra cuándo no se detectó (esto es común con este tipo de datos). Eso significa que los datos de salida están llenos de NA. Sin embargo, en este caso sabemos que la ausencia de un registro significa que no se vio el pez, por lo que podemos pedirle a pivot_wider() que complete estos valores faltantes con ceros:
fish_encounters %>% pivot_wider(
names_from = station,
values_from = seen,
values_fill = list(seen = 0)
)
También puede usar pivot_wider() para realizar una agregación simple. Por ejemplo, tome el conjunto de datos warpbreaks:
warpbreaks <- warpbreaks %>% as_tibble() %>% select(wool, tension, breaks)
warpbreaks
Este es un experimento diseñado con nueve repeticiones para cada combinación de wool (A y B) y tension (L, M, H):
warpbreaks %>% count(wool, tension)
¿Qué sucede si intentamos pivotar los niveles de wool en las columnas?
warpbreaks %>% pivot_wider(names_from = wool, values_from = breaks)
## Warning: Values are not uniquely identified; output will contain list-cols.
## * Use `values_fn = list` to suppress this warning.
## * Use `values_fn = length` to identify where the duplicates arise
## * Use `values_fn = {summary_fun}` to summarise duplicates
Recibimos una advertencia de que cada celda en la salida corresponde a múltiples celdas en la entrada. El comportamiento predeterminado produce columnas de lista, que contienen todos los valores individuales. Un resultado más útil sería el summary, medias para cada combinación de wool y tension:
warpbreaks %>%
pivot_wider(
names_from = wool,
values_from = breaks,
values_fn = list(breaks = mean)
)