Per due vettori logici, x
e y
, di lunghezza> 1E8, qual è il modo più veloce per calcolare le tabelle a croce 2x2?Il modo più veloce di cross-tabulare due vettori logici enormi in R
Sospetto che la risposta sia scrivere in C/C++, ma mi chiedo se c'è qualcosa in R che è già abbastanza intelligente su questo problema, in quanto non è raro.
codice di esempio, per 300M voci (sentitevi liberi di lasciare N = 1E8 se 3E8 è troppo grande;. Ho scelto una dimensione totale poco meno di 2,5 GB (2.4GB) ho preso di mira una densità di 0,02, solo per renderlo più interessante (si potrebbe usare un vettore scarsa, se questo aiuta, ma il tipo di conversione può richiedere tempo)
set.seed(0)
N = 3E8
p = 0.02
x = sample(c(TRUE, FALSE), N, prob = c(p, 1-p), replace = TRUE)
y = sample(c(TRUE, FALSE), N, prob = c(p, 1-p), replace = TRUE)
Alcuni metodi evidenti:.
table
bigtabulate
- Operazioni logiche semplici (ad es.
sum(x & y)
) - Vector moltiplicazione (boo)
data.table
- Alcuni di quanto sopra, con
parallel
dal pacchettomulticore
(o il nuovo pacchettoparallel
)
ho preso una pugnalata alla prima tre opzioni (vedi la mia risposta), ma sento che ci deve essere qualcosa di meglio e più veloce.
Trovo che table
lavori molto lentamente. bigtabulate
sembra eccessivo per una coppia di vettori logici. Infine, eseguire le operazioni logiche alla vaniglia sembra un kludge, e guarda ogni vettore troppe volte (3X? 7X?), Senza contare che riempie molta memoria aggiuntiva durante l'elaborazione, che è un enorme perdita di tempo.
La moltiplicazione di vettore è in genere una cattiva idea, ma quando il vettore è scarso, si può ottenere un vantaggio dall'archiviazione come tale e quindi dall'uso della moltiplicazione vettoriale.
Sentitevi liberi di variare N
e p
, se questo dimostrerà qualcosa di interessante comportamento delle funzioni di tabulazione. :)
Update 1. La mia prima risposta dà tempi su tre metodi ingenue, che è la base per credere table
è lento. Tuttavia, la cosa fondamentale da comprendere è che il metodo "logico" è grossolanamente inefficiente. Guardare cosa sta facendo:
- 4 operazioni logiche vettore
- 4 conversioni di tipo (logici a intero o FP - per
sum
) - 4 sommatorie vettore
- 8 assegnazioni (1 per l'operazione logica, 1 per la sommatoria)
Non solo, ma non è nemmeno compilato o parallelizzato. Eppure, batte ancora i pantaloni di table
.Si noti che bigtabulate
, con un tipo di conversione in più (1 * cbind...
) batte ancora table
.
Update 2. Per timore che qualcuno sottolineare che i vettori logici a sostegno R NA
, e che questa sarà una chiave nel sistema per questi tabulati croce (che è vero nella maggior parte dei casi), vorrei sottolineare che i miei vettori vengono da is.na()
o is.finite()
. :) Ho debug di NA
e altri valori non finiti - they've been a headache for me recently. Se non si sa se o non tutte le voci sono NA
, si potrebbe verificare con any(is.na(yourVector))
- questo sarebbe saggio prima di adottare alcune delle idee che sorgono in questo Q & A.
Update 3. Brandon Bertelsen ha fatto una domanda molto ragionevole nei commenti: perché usare così tanti dati quando un sottocampione (l'insieme iniziale, dopo tutto, è un campione ;-)) potrebbe essere adeguato ai fini della creazione di un cross-tabulazione? Non andare troppo lontano nelle statistiche, ma i dati derivano da casi in cui le osservazioni TRUE
sono molto rare, per entrambe le variabili. Uno è il risultato di un'anomalia di dati, l'altro a causa di un possibile bug nel codice (possibile errore, perché vediamo solo il risultato computazionale -. Pensare variabile x
come "Garbage In", e y
come "Garbage Out" come risultato , la questione è se i problemi in uscita causati dal codice sono gli unici casi in cui i dati sono anomali, o ci sono alcuni altri casi in cui buoni dati va male? (Questo è il motivo per cui ho chiesto a una domanda su stopping when a NaN
, NA
, or Inf
is encountered.)
questo spiega anche il motivo per cui il mio esempio ha una bassa probabilità di TRUE
valori, questi si verificano in realtà molto meno dello 0,1% del tempo
questo suggerisce un percorso soluzione diversa Sì: si suggerisce che possiamo usare due indici.?(Cioè le posizioni di TRUE
in ciascun set) e il conteggio delle intersezioni. Evitai impostato intersezioni perché ero bruciato un po 'indietro da Matlab (sì, questo è R, ma portare con me), che prima ordinare elementi di un insieme prima che fa un incrocio. (I vagamente la complessità era ancora più imbarazzante:. Come O(n^2)
anziché O(n log n)
)
Sono perplesso perché 'table' sembra lento a voi. È sempre stato veloce quando l'ho usato. (Ammettiamo che ci sono voluti 5 minuti per il tuo compito.) –
@DWin: Scusa se non ho risposto prima, stavo * aspettando * su 'table'. :) Vedi i miei risultati qui sotto. I risultati per 'table' sono semplicemente abissali. È stato battuto dal metodo dei vettori logici, che è esso stesso un metodo molto ingenuo e molto dispendioso: troppi accessi alla memoria, calcoli in virgola mobile e conversioni di tipi, non parallelizzati, ... l'orrore. Tuttavia, è ancora più veloce di 'table'. – Iterator
Sì. Anch'io sono stato sorpreso. La mia versione vettoriale logica era somma (x> y), somma (x