# package utilizzati ------------------------------------------------------
library(tidyverse)
library(janitor)
library(gapminder)Pivoting {tidyr}
Prepariamo l’ambiente di lavoro
Le funzioni per il pivoting sono contenuti nella libreria tidyr, automaticamente caricata quando si carica tidyverse. Per mostrare il funzionamento delle due funzioni principali per il pivoting carico quest’ultimo package unitamente al package janitor che sfrutto per uniformare i nomi di una delle due tabelle, ed al package `gapminder` che contiene una delle due tabelle dati.
Le due tabelle di esempio
I dati utilizzati per questo mostrare le operazioni di pivoting sono due tabelle disponibili in R ({datasets} e gapminder). Il primo dataset è però caricato da un file esterno di tipo testo air-passengers.txt perché il formato disponibile in R chiede alcune trasformazioni che non sono interessanti ai fini di questa presentazione:
# preparo le tabelle usate per gli esempi ---------------------------------
# un dataset sui numeri mensili di passeggeri di una compagnia aerea
# (il classico Box & Jenkins airline dataset)
air_passengers <- read_delim("../data/air-passengers.txt", delim = " ")Rows: 12 Columns: 13
── Column specification ────────────────────────────────────────────────────────
Delimiter: " "
dbl (13): year, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
air_passengers# A tibble: 12 × 13
year Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1949 112 118 132 129 121 135 148 148 136 119 104 118
2 1950 115 126 141 135 125 149 170 170 158 133 114 140
3 1951 145 150 178 163 172 178 199 199 184 162 146 166
4 1952 171 180 193 181 183 218 230 242 209 191 172 194
5 1953 196 196 236 235 229 243 264 272 237 211 180 201
6 1954 204 188 235 227 234 264 302 293 259 229 203 229
7 1955 242 233 267 269 270 315 364 347 312 274 237 278
8 1956 284 277 317 313 318 374 413 405 355 306 271 306
9 1957 315 301 356 348 355 422 465 467 404 347 305 336
10 1958 340 318 362 348 363 435 491 505 404 359 310 337
11 1959 360 342 406 396 420 472 548 559 463 407 362 405
12 1960 417 391 419 461 472 535 622 606 508 461 390 432
gap_data <- clean_names(gapminder)
gap_data# A tibble: 1,704 × 6
country continent year life_exp pop gdp_percap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779.
2 Afghanistan Asia 1957 30.3 9240934 821.
3 Afghanistan Asia 1962 32.0 10267083 853.
4 Afghanistan Asia 1967 34.0 11537966 836.
5 Afghanistan Asia 1972 36.1 13079460 740.
6 Afghanistan Asia 1977 38.4 14880372 786.
7 Afghanistan Asia 1982 39.9 12881816 978.
8 Afghanistan Asia 1987 40.8 13867957 852.
9 Afghanistan Asia 1992 41.7 16317921 649.
10 Afghanistan Asia 1997 41.8 22227415 635.
# ℹ 1,694 more rows
Per avere informazioni sul contenuto delle due tabelle è possibile consultare l’help:
help("AirPassengers")
help("gapminder")Tabella air_passenger: pivot_longer
La tabella air_passengers contiene i numeri di passeggeri classificati per anni (righe) e mesi (colonne).
E’ possibile sfruttare i verbi base di dplyr per calcolare le sintesi sulle colonne. Ecco un esempio con la funzione sum:
air_passengers |> summarise(across(-year, sum))# A tibble: 1 × 12
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 2901 2820 3242 3205 3262 3740 4216 4213 3629 3199 2794 3142
Tramite la funzione rowwise() è possibile usare la grammatica per la manipolazione dati lavorando sulle righe, ma è sicuramente più macchinoso:
air_passengers |>
rowwise() |>
mutate(somma = sum(across(everything()))) |>
select(year, somma)# A tibble: 12 × 2
# Rowwise:
year somma
<dbl> <dbl>
1 1949 3469
2 1950 3626
3 1951 3993
4 1952 4316
5 1953 4653
6 1954 4821
7 1955 5363
8 1956 5895
9 1957 6378
10 1958 6530
11 1959 7099
12 1960 7674
Si può naturalmente usare la sintassi base di R per lavorare sulle righe. Ad esempio posso accedere ad una riga, qui la prima:
air_passengers[1, ]# A tibble: 1 × 13
year Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1949 112 118 132 129 121 135 148 148 136 119 104 118
da cui escludo la prima colonna contenente l’anno ed effettuo la somma dei passeggeri:
sum(air_passengers[1, -1])[1] 1520
Altre due varianti possibili per sommare gli elementi su una riga (la funzione rowSums e la funzione più generale apply che può essere utilizzata per “applicare” qualunque funzione):
rowSums(air_passengers[, -1]) [1] 1520 1676 2042 2364 2700 2867 3408 3939 4421 4572 5140 5714
apply(air_passengers[,-1], 1, sum) [1] 1520 1676 2042 2364 2700 2867 3408 3939 4421 4572 5140 5714
Queste due ultime funzioni possono essere utilizzate anche per lavorare sulle colonne:
colSums(air_passengers[, -1]) Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2901 2820 3242 3205 3262 3740 4216 4213 3629 3199 2794 3142
apply(air_passengers[,-1], 2, sum) Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2901 2820 3242 3205 3262 3740 4216 4213 3629 3199 2794 3142
Oltre alla somma, esiste una funzione per il calcolo veloce della media (rowMeans) su un oggetto tabellare. Eccola in azione di seguito, con lo stesso risultato ottenuto poi con la funzione apply:
rowMeans(air_passengers[, -1]) [1] 126.6667 139.6667 170.1667 197.0000 225.0000 238.9167 284.0000 328.2500
[9] 368.4167 381.0000 428.3333 476.1667
apply(air_passengers[,-1], 1, mean) [1] 126.6667 139.6667 170.1667 197.0000 225.0000 238.9167 284.0000 328.2500
[9] 368.4167 381.0000 428.3333 476.1667
Ed ecco anche l’utilizzo delle analoghe funzioni sulle colonne:
colMeans(air_passengers[, -1]) Jan Feb Mar Apr May Jun Jul Aug
241.7500 235.0000 270.1667 267.0833 271.8333 311.6667 351.3333 351.0833
Sep Oct Nov Dec
302.4167 266.5833 232.8333 261.8333
apply(air_passengers[,-1], 2, mean) Jan Feb Mar Apr May Jun Jul Aug
241.7500 235.0000 270.1667 267.0833 271.8333 311.6667 351.3333 351.0833
Sep Oct Nov Dec
302.4167 266.5833 232.8333 261.8333
La funzione pivot_longer può essere utilizzata per trasformare la tabella in formato longer:
air_passengers_long <- pivot_longer(data = air_passengers,
cols = Jan:Dec,
names_to = "month",
values_to = "nr_passengers")
air_passengers_long# A tibble: 144 × 3
year month nr_passengers
<dbl> <chr> <dbl>
1 1949 Jan 112
2 1949 Feb 118
3 1949 Mar 132
4 1949 Apr 129
5 1949 May 121
6 1949 Jun 135
7 1949 Jul 148
8 1949 Aug 148
9 1949 Sep 136
10 1949 Oct 119
# ℹ 134 more rows
L’argomento cols richiede le colonne di cui si vuole effettuare il pivoting, o in alternativa le colonne da escludere utilizzando il segno -:
air_passengers_long <- pivot_longer(data = air_passengers,
cols = -year,
names_to = "month",
values_to = "nr_passengers")Una volta trasformata in formato longer, la tabella è più semplice da manipolare per calcolare sintesi. Ecco ad esempio il calcolo del totale dei passeggeri per anno:
air_passengers_long |>
group_by(year) |>
summarise(sum(nr_passengers))# A tibble: 12 × 2
year `sum(nr_passengers)`
<dbl> <dbl>
1 1949 1520
2 1950 1676
3 1951 2042
4 1952 2364
5 1953 2700
6 1954 2867
7 1955 3408
8 1956 3939
9 1957 4421
10 1958 4572
11 1959 5140
12 1960 5714
oppure dei passeggeri medi per ciascun mese:
air_passengers_long |>
group_by(month) |>
summarise(mean(nr_passengers))# A tibble: 12 × 2
month `mean(nr_passengers)`
<chr> <dbl>
1 Apr 267.
2 Aug 351.
3 Dec 262.
4 Feb 235
5 Jan 242.
6 Jul 351.
7 Jun 312.
8 Mar 270.
9 May 272.
10 Nov 233.
11 Oct 267.
12 Sep 302.
La trasformazione da formato wide a formato long è spesso necessario per sfruttare la logica di ggplot2 per le rappresentazioni grafiche:
air_passengers_long |>
ggplot() +
aes(x = year, y = nr_passengers, col = month) +
geom_line()
L’operazione inversa, pivot_wider, riporta la tabella da formato long a formato wide. Ecco l’effetto sulla tabella (per un altro esempio si rimanda al successivo paragrafo):
air_passengers_long |>
pivot_wider(id_cols = year,
names_from = month,
values_from = nr_passengers)# A tibble: 12 × 13
year Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1949 112 118 132 129 121 135 148 148 136 119 104 118
2 1950 115 126 141 135 125 149 170 170 158 133 114 140
3 1951 145 150 178 163 172 178 199 199 184 162 146 166
4 1952 171 180 193 181 183 218 230 242 209 191 172 194
5 1953 196 196 236 235 229 243 264 272 237 211 180 201
6 1954 204 188 235 227 234 264 302 293 259 229 203 229
7 1955 242 233 267 269 270 315 364 347 312 274 237 278
8 1956 284 277 317 313 318 374 413 405 355 306 271 306
9 1957 315 301 356 348 355 422 465 467 404 347 305 336
10 1958 340 318 362 348 363 435 491 505 404 359 310 337
11 1959 360 342 406 396 420 472 548 559 463 407 362 405
12 1960 417 391 419 461 472 535 622 606 508 461 390 432
Tabella gapminder: pivot_longer
La tabella gapminder è invece in classico formato long, per cui è agevole sfruttare i verbi del package dplyr:
gap_data |>
group_by(continent, year) |>
summarise(life_exp_avg = mean(life_exp))`summarise()` has grouped output by 'continent'. You can override using the
`.groups` argument.
# A tibble: 60 × 3
# Groups: continent [5]
continent year life_exp_avg
<fct> <int> <dbl>
1 Africa 1952 39.1
2 Africa 1957 41.3
3 Africa 1962 43.3
4 Africa 1967 45.3
5 Africa 1972 47.5
6 Africa 1977 49.6
7 Africa 1982 51.6
8 Africa 1987 53.3
9 Africa 1992 53.6
10 Africa 1997 53.6
# ℹ 50 more rows
Utilizziamo la tabella gapminder anche per illustrare la logica del package ggplot2. Può essere a volta utile trasformare la tabella di sintesi appena calcolato in formato wide per inserirla ad esempio in un report. Possiamo ottenerla velocemente usando la funzione pivot_wider:
gap_data |>
group_by(continent, year) |>
summarise(life_exp_avg = mean(life_exp)) |>
pivot_wider(id_cols = year,
names_from = continent,
values_from = life_exp_avg)`summarise()` has grouped output by 'continent'. You can override using the
`.groups` argument.
# A tibble: 12 × 6
year Africa Americas Asia Europe Oceania
<int> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1952 39.1 53.3 46.3 64.4 69.3
2 1957 41.3 56.0 49.3 66.7 70.3
3 1962 43.3 58.4 51.6 68.5 71.1
4 1967 45.3 60.4 54.7 69.7 71.3
5 1972 47.5 62.4 57.3 70.8 71.9
6 1977 49.6 64.4 59.6 71.9 72.9
7 1982 51.6 66.2 62.6 72.8 74.3
8 1987 53.3 68.1 64.9 73.6 75.3
9 1992 53.6 69.6 66.5 74.4 76.9
10 1997 53.6 71.2 68.0 75.5 78.2
11 2002 53.3 72.4 69.2 76.7 79.7
12 2007 54.8 73.6 70.7 77.6 80.7