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 sonoNA
nella nostra tabella finale. Se vediamo inaspettatamente dati mancanti di questo tipo, possiamo risalire all'osservazione mancante nella tabellageoDT
e 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