Perché i panda si sono uniti in python più velocemente rispetto ai data.table si sono uniti in R nel 2012?


160

Recentemente ho trovato il panda libreria per Python, che secondo questo benchmark esegue molto veloce si fonde in memoria. È anche più veloce del pacchetto data.table in R (la mia lingua preferita per l'analisi).

Perché è pandasmolto più veloce di data.table? È a causa di un vantaggio di velocità intrinseco che Python ha su R o c'è qualche compromesso di cui non sono a conoscenza? C'è un modo per eseguire i join interni ed esterni data.tablesenza ricorrere a merge(X, Y, all=FALSE)e merge(X, Y, all=TRUE)?

Confronto

Ecco il codice R e il codice Python utilizzati per confrontare i vari pacchetti.


10
@JoshuaUlrich: IIRC data.tableeredita da data.frame, ma si basa sul codice C sotto il cofano.
digEmAll

4
@Joshua Cosa intendi con "data.frames sono lenti anche se li manipoli in C"? È relativo a qualcos'altro? E lento a cosa?
Matt Dowle il

12
@JoshuaUlrich Ho appena notato che questo commento non è mai stato messo a letto. Quindi, per chiarire: è set()stato aggiunto data.tablesubito dopo questa discussione. Molto simile :=ma evita il piccolo sovraccarico di [.data.tablequando è in loop ed è di conseguenza più veloce matrix. Pertanto, data.frame può essere manipolato alla stessa velocità della matrice. Il benchmark è qui .
Matt Dowle,

5
Possiamo ottenere una versione aggiornata di questo benchmark, è abbastanza chiaro che questo banco era in realtà un caso limite e che questo è stato risolto ormai. Dato che tutti i benchmark che ho visto mostrano che data.table è più veloce, mi piacerebbe vedere quali sono i numeri di unione?
statquant

3
@statquant Non ho eseguito il benchmark originale, ma mi piacerebbe davvero vedere Wes aggiornare il benchmark.
Zach,

Risposte:


120

Sembra che Wes abbia scoperto un problema noto in data.tablequando il numero di stringhe ( livelli ) uniche è grande: 10.000.

Non Rprof()rivelare la maggior parte del tempo speso nella chiamata sortedmatch(levels(i[[lc]]), levels(x[[rc]])? Questo non è in realtà il join stesso (l'algoritmo), ma un passaggio preliminare.

Recenti sforzi sono stati fatti per consentire le colonne di caratteri nelle chiavi, che dovrebbero risolvere il problema integrandosi più da vicino con la tabella hash della stringa globale di R. Alcuni risultati di benchmark sono già riportati da test.data.table()ma quel codice non è ancora collegato per sostituire i livelli con i livelli corrispondenti.

I panda si uniscono più velocemente rispetto data.tablealle normali colonne intere? Questo dovrebbe essere un modo per isolare l'algoritmo stesso rispetto ai problemi dei fattori.

Inoltre, data.tableha in mente le serie temporali . Due aspetti: i) chiavi ordinate su più colonne come (id, datetime) ii) join prevalente ( roll=TRUE) noto anche come ultima osservazione portata avanti.

Avrò bisogno di un po 'di tempo per confermare poiché è il primo che ho visto del confronto data.tablecome presentato.


AGGIORNAMENTO da data.table v1.8.0 rilasciato luglio 2012

  • Funzione interna sortmatch () rimossa e sostituita con chmatch () quando si abbinano i livelli a livelli x per colonne di tipo 'fattore'. Questo passaggio preliminare stava causando un rallentamento (noto) significativo quando il numero di livelli di una colonna fattoriale era elevato (ad esempio> 10.000). Esacerbato nei test di unione di quattro di queste colonne, come dimostrato da Wes McKinney (autore del pacchetto Pandas di Python). Ad esempio 1 milione di stringhe di cui 600.000 uniche è ora ridotto da 16 a 0,5 secondi.

anche in quella versione c'era:

  • le colonne di caratteri sono ora consentite nelle chiavi e sono da considerare come fattori. data.table () e setkey () non costringono più il carattere al fattore. I fattori sono ancora supportati. Implementa FR # 1493, FR # 1224 e (parzialmente) FR # 951.

  • Nuove funzioni chmatch () e% chin%, versioni più veloci di match () e% in% per i vettori di caratteri. Viene utilizzata la cache di stringa interna di R (non viene creata alcuna tabella hash). Sono circa 4 volte più veloci di match () nell'esempio in? Chmatch.

A partire da settembre 2013 data.table è v1.8.10 su CRAN e stiamo lavorando su v1.9.0. NEWS è aggiornato in tempo reale.


Ma come ho scritto in origine, sopra:

data.tableha in mente le serie temporali . Due aspetti: i) chiavi ordinate su più colonne come (id, datetime) ii) join prevalente ( roll=TRUE) noto anche come ultima osservazione portata avanti.

Quindi il panda equi join di due colonne di caratteri è probabilmente ancora più veloce di data.table. Dal momento che sembra che hash le due colonne combinate. data.table non esegue l'hashing della chiave perché ha in mente i join ordinati prevalenti. Una "chiave" in data.table è letteralmente solo il tipo di ordinamento (simile a un indice cluster in SQL; ovvero, è così che i dati vengono ordinati nella RAM). Nell'elenco è necessario aggiungere chiavi secondarie, ad esempio.

In sintesi, la differenza di velocità evidente evidenziata da questo particolare test della colonna di due caratteri con oltre 10.000 stringhe uniche non dovrebbe essere così grave ora, poiché il problema noto è stato risolto.


6
Se fornisci un caso di prova per un set di dati ragionevolmente ampio e realistico, sarò felice di eseguire i benchmark. Anche tu sei il benvenuto. In realtà non ho ancora ottimizzato il codice per il caso chiave join intero (mettilo nella mia lista delle cose da fare!), Ma puoi aspettarti prestazioni significativamente migliori rispetto al caso stringa dato lo studio della tabella hash nella presentazione collegata.
Wes McKinney,

22
Non uso nessuna di queste librerie ma mi fa piacere vedere una risposta costruttiva dal lato R nella forma di Matthew Dowle.
SlowLearner,

3
Ecco alcuni risultati di Rprof pastie.org/3258362 . Sembra che il 20-40% del tempo sia trascorso in corrispondenza dell'ordinamento in base al tipo di join. Dovrà esaminare le colonne di numeri interi un'altra volta. Ho fatto un problema con Panda GitHub per ricordarmi di ottimizzare quel caso ( github.com/wesm/pandas/issues/682 )
Wes McKinney,

14
@AndyHayden Sono stati apportati miglioramenti qualche tempo fa. Modificherò nelle voci NEWS. Wes ha scelto un test specifico (che unisce due colonne di caratteri) che ha giocato su quel problema noto. Se avesse scelto colonne intere sarebbe stato diverso. E se mi avesse dato un avvertimento prima di presentare il benchmark alla conferenza, avrei potuto dirgli di più sul problema noto.
Matt Dowle,

191

Il motivo per cui i panda è più veloce è perché ho escogitato un algoritmo migliore, che viene implementato con molta attenzione usando un'implementazione veloce della tabella hash - klib e in C / Cython per evitare l'overhead dell'interprete Python per le parti non vettorizzabili. L'algoritmo è descritto in dettaglio nella mia presentazione: Uno sguardo al design e allo sviluppo dei panda .

Il confronto con data.tableè in realtà un po 'interessante perché l'intero punto di R data.tableè che contiene indici precalcolati per varie colonne per accelerare operazioni come la selezione e l'unione dei dati. In questo caso (Data Database Join), DataFrame di Panda non contiene informazioni pre-calcolate che vengono utilizzate per l'unione, per così dire è un'unione "fredda". Se avessi memorizzato le versioni fattorizzate delle chiavi del join, il join sarebbe significativamente più veloce, poiché la fattorizzazione è il maggiore collo di bottiglia per questo algoritmo.

Vorrei anche aggiungere che il design interno del DataFrame di Panda è molto più suscettibile a questo tipo di operazioni rispetto al data.frame di R (che è solo un elenco di array internamente).


76
Certo, ora che hai capito tutto in Python, dovrebbe essere facile da tradurre in R;)
Hadley,

37
Ma perché qualcuno lo vorrebbe mai? :)
ely,

9
Umm ... forse perché vorrebbero che le operazioni sui dati fossero più veloci in R? Solo indovinando :))
lebatsnok,

28
Ciao Wes-- sembra che i tuoi risultati siano data.tablestati principalmente guidati da un bug che da allora è stato corretto. Hai qualche possibilità di rieseguire il tuo benchmark e scrivere un post sul blog aggiornato?
Zach,

6
Zach assicurati di controllare questo: github.com/Rdatatable/data.table/wiki/Benchmarks-:-Grouping
Merik

37

Questo argomento ha due anni ma sembra un luogo probabile in cui le persone possano atterrare quando cercano confronti tra Panda e data.table

Dal momento che entrambi questi si sono evoluti nel tempo, voglio pubblicare un confronto relativamente più recente (dal 2014) qui per gli utenti interessati: https://github.com/Rdatatable/data.table/wiki/Benchmarks-:-Grouping

Sarebbe interessante sapere se Wes e / o Matt (che, a proposito, sono rispettivamente creatori di Panda e data.table e hanno entrambi commentato sopra) hanno qualche notizia da aggiungere anche qui.

-- AGGIORNARE --

Un commento pubblicato di seguito da jangorecki contiene un link che ritengo molto utile: https://github.com/szilard/benchm-database

https://github.com/szilard/benchm-databases/blob/master/plot.png

Questo grafico mostra i tempi medi di aggregazione e le operazioni di join per diverse tecnologie ( inferiore = più veloce ; confronto aggiornato per ultimo a settembre 2016). È stato davvero educativo per me.

Tornando alla domanda, R DT keye R DTfare riferimento alle calettati / sapori non codificate di R data.table e capita di essere più veloce in questo benchmark di Pandas di Python ( Py pandas).


1
Stavo per pubblicare questo! Grazie per l'aggiunta.
Zach,

7
@Zach vedi questo: github.com/szilard/benchm-database e anche questo è carino: speakerdeck.com/szilard/…
jangorecki

1
@Zach dopo quattro anni sono finalmente arrivati ​​nuovi risultati di benchmark, vedi la mia risposta di seguito.
jangorecki,

7

Ci sono grandi risposte, fatte in particolare dagli autori di entrambi gli strumenti di cui fa domanda. La risposta di Matt spiega il caso riportato nella domanda, che è stato causato da un bug e non da un algoritmo di fusione. Il bug è stato corretto il giorno successivo, più di 7 anni fa.

Nella mia risposta fornirò alcuni tempi aggiornati per l'operazione di fusione di data.table e panda. Si noti che la fusione plyr e base R non sono incluse.

I tempi che sto presentando provengono dal progetto db-benchmark , un benchmark riproducibile in esecuzione continua. Aggiorna gli strumenti alle versioni recenti e riesegue gli script di benchmark. Funziona con molte altre soluzioni software. Se sei interessato a Spark, Dask e pochi altri, assicurati di controllare il link.


A partire da ora ... (ancora da implementare: ancora una dimensione dei dati e altre 5 domande)

Testiamo 2 diverse dimensioni di dati della tabella LHS.
Per ognuna di quelle dimensioni di dati eseguiamo 5 domande di unione diverse.

q1: raccordo interno LHS RHS- piccolo su intero
q2: raccordo interno LHS medio RHS su intero
q3: raccordo esterno LHS medio RHS su intero
q4: raccordo interno LHS medio RHS su fattore (categoriale)
q5: raccordo interno LHS RHS- grande su intero

La tabella RHS è di 3 diverse dimensioni

  • piccolo si traduce in dimensioni di LHS / 1e6
  • il mezzo si traduce in dimensioni di LHS / 1e3
  • grande si traduce in dimensioni di LHS

In tutti i casi esiste circa il 90% delle righe corrispondenti tra LHS e RHS e nessun duplicato nella colonna di giunzione RHS (nessun prodotto cartesiano).


A partire da ora (in esecuzione il 2 novembre 2019)

Panda 0.25.3 rilasciato il 1 novembre 2019
data.table 0.12.7 (92abb70) rilasciato il 2 novembre 2019

I tempi seguenti sono espressi in secondi, per due diverse dimensioni di dati di LHS. La colonna pd2dtviene aggiunta al rapporto di memorizzazione dei campi di quante volte i panda sono più lenti di data.table.

  • 0,5 GB di dati LHS
+-----------+--------------+----------+--------+
| question  |  data.table  |  pandas  |  pd2dt |
+-----------+--------------+----------+--------+
| q1        |        0.51  |    3.60  |      7 |
| q2        |        0.50  |    7.37  |     14 |
| q3        |        0.90  |    4.82  |      5 |
| q4        |        0.47  |    5.86  |     12 |
| q5        |        2.55  |   54.10  |     21 |
+-----------+--------------+----------+--------+
  • 5 GB di dati LHS
+-----------+--------------+----------+--------+
| question  |  data.table  |  pandas  |  pd2dt |
+-----------+--------------+----------+--------+
| q1        |        6.32  |    89.0  |     14 |
| q2        |        5.72  |   108.0  |     18 |
| q3        |       11.00  |    56.9  |      5 |
| q4        |        5.57  |    90.1  |     16 |
| q5        |       30.70  |   731.0  |     23 |
+-----------+--------------+----------+--------+

Grazie per l'aggiornamento dal futuro! Potresti aggiungere una colonna per l'implementazione R vs python di data.table?
Zach,

1
Penso che sia bello andare sul sito Web e controllarlo, anche per guardare R dt vs panda. E pyDT non faceva davvero parte della domanda originale.
jangorecki,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.