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, ...)ogroup_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 conNA.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à.