data.table
Si unisce e si fonde
Ricerca…
introduzione
?`[.data.table` per i documenti ufficiali.
Sintassi
- x [i, on, j]
# join: data.table x & data.table o lista i - x [! i, on, j]
# anti-join
Osservazioni
Lavorare con tabelle con chiave
Se x & i hanno una chiave o x è calettati per abbinare i 's prime colonne, allora la on possono essere ignorati come x[i] .
Nomi di colonne disambiguanti in comune
In j di x[i, on, j] , le colonne di i possono essere riferite con prefissi i.* .
Raggruppamento su sottoinsiemi
In j di x[i, on, j, by=.EACHI] , j viene calcolato per ogni riga di i .
Questo è l'unico valore by vale la pena utilizzare. Per qualsiasi altro valore, le colonne di i non sono disponibili.
Aggiorna valori in un join
Quando i dati sono "ordinati" , è spesso organizzato in più tabelle. Per combinare i dati per l'analisi, dobbiamo "aggiornare" una tabella con i valori di un'altra.
Ad esempio, potremmo avere dati di vendita per le prestazioni, in cui gli attributi dell'esecutore (il loro budget) e della posizione (la sua popolazione) sono memorizzati in tabelle separate:
set.seed(1)
mainDT = data.table(
p_id = rep(LETTERS[1:2], c(2,4)),
geo_id = sample(rep(state.abb[c(1,25,50)], 3:1)),
sales = sample(100, 6)
)
pDT = data.table(id = LETTERS[1:2], budget = c(60, 75))
geoDT = data.table(id = state.abb[c(1,50)], pop = c(100, 200))
mainDT # sales data
# p_id geo_id sales
# 1: A AL 95
# 2: A WY 66
# 3: B AL 62
# 4: B MO 6
# 5: B AL 20
# 6: B MO 17
pDT # performer attributes
# id budget
# 1: A 60
# 2: B 75
geoDT # location attributes
# id pop
# 1: AL 100
# 2: WY 200
Quando siamo pronti per fare qualche analisi, dobbiamo prendere le variabili da queste altre tabelle:
DT = copy(mainDT)
DT[pDT, on=.(p_id = id), budget := i.budget]
DT[geoDT, on=.(geo_id = id), pop := i.pop]
# p_id geo_id sales budget pop
# 1: A AL 95 60 100
# 2: A WY 66 60 200
# 3: B AL 62 75 100
# 4: B MO 6 75 NA
# 5: B AL 20 75 100
# 6: B MO 17 75 NA
Viene mainDT una copy per evitare di contaminare i dati grezzi, ma potremmo invece lavorare direttamente su mainDT .
Vantaggi nell'utilizzo di tabelle separate
I vantaggi di questa struttura sono trattati nel documento sui dati ordinati, ma in questo contesto:
Tracciamento dei dati mancanti. Solo le righe che corrispondono nell'unione ricevono un compito. Non abbiamo dati per
geo_id == "MO"sopra, quindi le sue variabili sonoNAnella nostra tabella finale. Se vediamo inaspettatamente dati mancanti di questo tipo, possiamo risalire all'osservazione mancante nella tabellageoDTe indagare da lì se abbiamo un problema di dati che può essere risolto.Comprensibilità. Nel costruire il nostro modello statistico, potrebbe essere importante tenere a mente che il
budgetè costante per ogni attore. In generale, capire la struttura dei dati paga i dividendi.Dimensione della memoria. Potrebbe esserci un gran numero di attributi esecutore e posizione che non finiscono nel modello statistico. In questo modo, non è necessario includerli nella (possibilmente massiccia) tabella utilizzata per l'analisi.
Determinazione a livello di codice delle colonne
Se ci sono molte colonne in pDT , ma vogliamo solo selezionarne alcune, possiamo usarle
p_cols = "budget"
DT[pDT, on=.(p_id = id), (p_cols) := mget(sprintf("i.%s", p_cols))]
Le parentesi intorno (p_cols) := sono essenziali, come indicato nel documento sulla creazione di colonne .
Equi-join
# example data
a = data.table(id = c(1L, 1L, 2L, 3L, NA_integer_), x = 11:15)
# id x
# 1: 1 11
# 2: 1 12
# 3: 2 13
# 4: 3 14
# 5: NA 15
b = data.table(id = 1:2, y = -(1:2))
# id y
# 1: 1 -1
# 2: 2 -2
Intuizione
Pensa a x[i] come selezionando un sottoinsieme di x per ogni riga di i . Questa sintassi rispecchia il subset matrice in base R ed è coerente con il primo argomento che significa "dove", in DT[where, select|update|do, by] .
Ci si potrebbe chiedere perché valga la pena imparare questa nuova sintassi, dato che merge(x,i) funziona ancora con data.tables. La risposta breve è che di solito vogliamo unire e quindi fare qualcosa di più. La sintassi x[i] cattura concisamente questo schema di utilizzo e consente anche un calcolo più efficiente. Per una spiegazione più dettagliata, leggere le domande frequenti 1.12 e 2.14 .
Gestione di righe con corrispondenza multipla
Per impostazione predefinita, viene restituita ogni riga di a corrispondenza di ogni riga di b :
a[b, on="id"]
# id x y
# 1: 1 11 -1
# 2: 1 12 -1
# 3: 2 13 -2
Questo può essere ottimizzato con mult :
a[b, on="id", mult="first"]
# id x y
# 1: 1 11 -1
# 2: 2 13 -2
Gestione di righe non corrispondenti
Per impostazione predefinita, le righe senza precedenti di a ancora la loro comparsa nel risultato:
b[a, on="id"]
# id y x
# 1: 1 -1 11
# 2: 1 -1 12
# 3: 2 -2 13
# 4: 3 NA 14
# 5: NA NA 15
Per nasconderli, usa nomatch :
b[a, on="id", nomatch=0]
# id y x
# 1: 1 -1 11
# 2: 1 -1 12
# 3: 2 -2 13
Si noti che x[i] tenterà di far corrispondere le NA in i .
Le partite di conteggio sono tornate
Per contare il numero di corrispondenze per ogni riga di i , utilizzare .N e by=.EACHI .
b[a, on="id", .N, by=.EACHI]
# id N
# 1: 1 1
# 2: 1 1
# 3: 2 1
# 4: 3 0
# 5: NA 0