Menu

Ristrutturare dati in R: pivot_wider e pivot_longer (largo e lungo)

I formati di dati largo e lungo e come passare dall'uno all'altro: pivot_longer() e pivot_wider() di tidyr, i vecchi nomi spread/gather e reshape() di R base.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Largo e lungo: gli stessi dati, due forme

Ogni domanda sulla ristrutturazione dei dati si riduce a una distinzione, quindi vediamola. Ecco un piccolo dataset, le vendite trimestrali di due città, costruito in entrambe le forme:

Informazioni identiche, geometria diversa. Il formato largo ha una riga per città e una colonna per trimestre: il trimestre vive nei nomi delle colonne. Il formato lungo ha una riga per osservazione (città × trimestre), con il trimestre retrocesso a colonna ordinaria e ogni misura in un'unica colonna sales.

Nessuna delle due forme è "corretta": servono padroni diversi. Il formato largo è quello che leggono le persone e che esportano i fogli di calcolo: compatto, confrontabile a colpo d'occhio. Il formato lungo è quello che consumano gli strumenti, e passare dall'uno all'altro si chiama pivoting (o ristrutturazione, è la stessa cosa).

Perché il formato lungo vince nell'analisi

Guarda cosa ha fatto il formato largo al concetto di "trimestre": ha fatto a pezzi una variabile trasformandola in nomi di colonna. Niente può fare calcoli con un nome di colonna. Nel formato lungo, quarter torna a essere un dato, e tutta la cassetta degli attrezzi dell'analisi per gruppi si accende:

  • aggregate(sales ~ quarter, ...) o group_by(quarter): impossibili nel formato largo, dove ogni trimestre è una colonna separata da gestire a mano (i riepiloghi per gruppo presuppongono tutti dati lunghi).
  • ggplot2 associa colonne alle estetiche: aes(x = quarter, y = sales, color = city) ha bisogno che quelle tre colonne esistano. Rappresentare dati larghi è una lotta continua; rappresentare dati lunghi è una riga.
  • Aggiungere Q3 significa aggiungere righe, senza cambiare lo schema, mentre nel formato largo nasce una nuova colonna di cui ogni passaggio successivo deve venire a conoscenza.

La regola pratica: memorizza e analizza in formato lungo, presenta in formato largo. Ecco perché le due conversioni qui sotto si usano così tanto: i dati arrivano larghi dai fogli di calcolo, vengono allungati per l'analisi e poi di nuovo allargati per la tabella finale del report.

Da largo a lungo: pivot_longer()

Il pacchetto tidyr (il fratello di dplyr nel tidyverse) si occupa della ristrutturazione moderna. I suoi frammenti qui sono statici, perché la sandbox esegue solo R base. Allungare richiede tre decisioni, un argomento ciascuna:

library(tidyr)

long <- pivot_longer(wide,
    cols      = c(Q1, Q2),      # which columns to stack
    names_to  = "quarter",      # new column that receives the old NAMES
    values_to = "sales"         # new column that receives the cell VALUES
)

Vediamolo passo per passo: cols indica le colonne da sciogliere (funzionano anche la sintassi di intervallo Q1:Q2 e helper come starts_with("Q"), comodi quando sono venti). Ogni cella scelta diventa una riga; la colonna da cui proviene finisce in quarter, il numero stesso in sales. Le colonne non elencate in cols (qui city) vengono trattate come identificatori e si ripetono lungo le righe. Il risultato è esattamente il data frame long stampato sopra.

Da lungo a largo: pivot_wider()

Il viaggio inverso richiede due decisioni: da dove vengono i nuovi nomi di colonna e cosa li riempie.

wide <- pivot_wider(long,
    names_from  = quarter,   # distinct values here become new columns
    values_from = sales      # these values fill the cells
)

Ogni valore distinto di quarter (Q1, Q2) diventa una colonna; ogni cella viene riempita con il valore di sales della riga corrispondente a quella città e a quel trimestre. Le colonne rimanenti (city) fanno da identificatori di riga: una riga di output per ogni combinazione distinta. Una città a cui manca un trimestre riceve NA in quella cella (l'argomento values_fill lo sostituisce con qualcos'altro, per esempio values_fill = 0 per i conteggi).

Nei tutorial più vecchi incontrerai anche la generazione precedente: spread() è pivot_wider() e gather() è pivot_longer(), superate da tidyr 1.0, ancora funzionanti, e non vale la pena impararle oltre a saperle riconoscere.

R base ha reshape(): un avvertimento onesto

R base può farlo senza pacchetti, con reshape(), una funzione così famosa per la sua confusione che la sua stessa documentazione in passato se ne scusava. È stata progettata attorno al vocabolario degli studi longitudinali (idvar, timevar, direction), i nomi degli argomenti si adattano male ai dati di tutti i giorni, e tutti li dimenticano da un uso all'altro. Però funziona:

Nota i nomi nell'output: sales.Q1, sales.Q2, con il nome della colonna dei valori fuso con ciascuno. Va bene in caso di necessità, in un ambiente senza dipendenze o quando la incontri in codice vecchio. Ma se ristrutturi dati più di una volta all'anno, install.packages("tidyr") è il consiglio onesto: è l'unica attività di manipolazione dei dati in cui lo strumento di R base costa davvero più della dipendenza che fa risparmiare.

La trappola delle chiavi duplicate quando allarghi

Allargare presuppone che ogni combinazione di identificatore + nome individui un solo valore. Se Lima ha due righe Q1, quale numero va nell'unica cella Q1? pivot_wider() si rifiuta di indovinare: emette un avviso (values are not uniquely identified) e mette nella cella una list-column, cioè un data frame con liste annidate, che rompe la prossima cosa che ci fai.

Quando vedi quell'avviso, non ricorrere per prima cosa alla via d'uscita values_fn: chiediti perché esistono i duplicati. Di solito i dati hanno una granularità più fine di quanto pensavi (righe giornaliere, non trimestrali, quindi prima riassumi e poi allarghi) oppure un join a monte ha duplicato le righe. values_fn = mean (o sum) è la soluzione legittima solo quando sai dire ad alta voce con quale aggregazione devono essere fusi i duplicati. reshape() qui è peggio: tiene in silenzio il primo duplicato e scarta il resto, con solo un avviso facile da non notare.

Cosa ti porti a casa

  • Largo: variabili nascoste nei nomi delle colonne, pensato per la lettura. Lungo: una riga per osservazione, pensato per l'analisi e ggplot2.
  • Memorizza e analizza in formato lungo, presenta in formato largo.
  • pivot_longer(cols, names_to, values_to) impila colonne in righe; le colonne non elencate diventano identificatori ripetuti.
  • pivot_wider(names_from, values_from) distribuisce righe in colonne; i buchi si riempiono con NA.
  • spread()/gather() sono i vecchi nomi; reshape() di R base funziona ma è notoriamente scomoda.
  • Coppie duplicate di identificatore + nome rendono ambiguo l'allargamento: prima riassumi, non limitarti a zittire l'avviso.

Prossimo passo: leggere dati reali da file, con read.csv() e i suoi spigoli.

Domande frequenti

Qual è la differenza tra dati in formato largo e lungo in R?

Stessi dati, forme diverse. Il formato largo distribuisce una variabile su più colonne (per esempio una colonna per trimestre): una riga per soggetto, pensato per la lettura umana. Il formato lungo la impila in righe: una riga per osservazione, con una colonna per il nome e una per il valore, pensato per l'analisi per gruppi e ggplot2.

Come si convertono dati da formato largo a lungo in R?

pivot_longer(df, cols = Q1:Q4, names_to = "quarter", values_to = "sales") di tidyr impila le colonne scelte in due nuove colonne: i vecchi nomi di colonna finiscono nella colonna names_to, i valori delle celle nella colonna values_to.

Come si convertono dati da formato lungo a largo in R?

pivot_wider(df, names_from = quarter, values_from = sales) di tidyr distribuisce le righe in colonne: ogni valore distinto di names_from diventa una colonna, riempita con i valori corrispondenti di values_from. Le combinazioni mancanti diventano NA.

Cosa ha sostituito spread e gather in R?

pivot_wider() ha sostituito spread() e pivot_longer() ha sostituito gather() in tidyr 1.0 (2019). Le vecchie funzioni funzionano ancora, e le vedrai nei tutorial più vecchi, ma tutto il codice nuovo dovrebbe usare la coppia pivot_*, che ha argomenti più chiari e più funzionalità.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA