Por que as mesclas de pandas em python são mais rápidas que as mesclas data.table no R em 2012?

160

Recentemente, deparei com a biblioteca de pandas para python, que de acordo com esse benchmark realiza fusões na memória muito rápidas. É ainda mais rápido que o pacote data.table no R (minha língua preferida para análise).

Por que é pandasmuito mais rápido que data.table? É por causa de uma vantagem inerente à velocidade que o python possui sobre o R ou há alguma desvantagem que não conheço? Existe uma maneira de realizar interior e exterior junta-se data.tablesem recorrer a merge(X, Y, all=FALSE)e merge(X, Y, all=TRUE)?

Comparação

Aqui está o código R e o código Python usado para comparar os vários pacotes.

Zach
fonte
10
@ JosuéUlrich: O IIRC data.tableapenas herda data.frame, mas depende do código C sob o capô.
digEmAll
4
@ Josué O que você quer dizer com "data.frames são lentos, mesmo se você os manipular em C"? Isso é relativo a outra coisa? E lento no que?
precisa saber é o seguinte
12
@ JoshuaUlrich Acabei de notar que essa trilha de comentários nunca foi colocada na cama. Então, para esclarecer: set()foi adicionado data.tablelogo após esta discussão. Muito parecido, :=mas evita a pequena sobrecarga de [.data.tablequando está em loop e, consequentemente, é tão rápido quanto matrix. Portanto, data.frame pode ser manipulado tão rápido quanto a matriz. A Benchmark está aqui .
quer
5
Podemos obter uma versão atualizada desse benchmark, é bastante claro que esse banco era realmente um caso de ponta e que isso já está resolvido. Dado que todos os benchmarks que eu vi mostram que data.table é mais rápido, eu gostaria de ver qual é o número de mesclagem?
statquant
3
@statquant Não executei o benchmark original, mas adoraria ver Wes atualizando o benchmark.
Zach

Respostas:

120

Parece que Wes pode ter descoberto um problema conhecido data.tablequando o número de seqüências únicas ( níveis ) é grande: 10.000.

Será que Rprof()revelam a maior parte do tempo gasto na chamadasortedmatch(levels(i[[lc]]), levels(x[[rc]]) ? Esta não é realmente a junção em si (o algoritmo), mas uma etapa preliminar.

Esforços recentes foram feitos para permitir colunas de caracteres nas chaves, o que deve resolver esse problema, integrando-se mais de perto com a própria tabela de hash de cadeia global de R. Alguns resultados de benchmark já são relatados portest.data.table() mas esse código ainda não está conectado para substituir os níveis pelos níveis correspondentes.

Os pandas são mesclados mais rapidamente do que data.tablenas colunas inteiras regulares? Essa deve ser uma maneira de isolar o algoritmo em si versus questões de fatores.

Além disso, data.tabletem séries temporais em mente. Dois aspectos: i) chaves ordenadas por várias colunas , como (id, datetime); ii) junção predominante rápida (roll=TRUE ), ou seja, a última observação levada adiante.

Precisarei de algum tempo para confirmar, pois é a primeira vez que vejo a comparação data.tablecomo apresentada.


ATUALIZAÇÃO da data.table v1.8.0 lançada em julho de 2012

  • A função interna classificadamatch () foi removida e substituída por chmatch () ao corresponder os níveis i aos níveis x das colunas do tipo 'fator'. Essa etapa preliminar estava causando uma desaceleração significativa (conhecida) quando o número de níveis de uma coluna de fator era grande (por exemplo,> 10.000). Exacerbado nos testes de união de quatro dessas colunas, como demonstrado por Wes McKinney (autor do pacote Pandas do Python). A correspondência de 1 milhão de strings, das quais 600.000 são únicas, agora é reduzida de 16s para 0,5s, por exemplo.

também nessa versão foi:

  • colunas de caracteres agora são permitidas em chaves e são preferidas ao fator. data.table () e setkey () não obrigam mais o caractere a fatorar. Fatores ainda são suportados. Implementa FR # 1493, FR # 1224 e (parcialmente) FR # 951.

  • Novas funções chmatch () e% chin%, versões mais rápidas de match () e% em% para vetores de caracteres. O cache interno de string de R é utilizado (nenhuma tabela de hash é criada). Eles são cerca de 4 vezes mais rápidos que match () no exemplo em? Chmatch.

Em setembro de 2013, data.table é a v1.8.10 no CRAN e estamos trabalhando na v1.9.0. NEWS é atualizado ao vivo.


Mas como eu escrevi originalmente, acima:

data.tabletem séries temporais em mente. Dois aspectos: i) chaves ordenadas por várias colunas , como (id, datetime); ii) junção prevalecente rápida ( roll=TRUE), ou seja, a última observação levada adiante.

Portanto, a junção equi do Pandas de duas colunas de caracteres provavelmente ainda é mais rápida que a tabela de dados. Desde que soa como hashes as duas colunas combinadas. data.table não hash a chave porque tem em mente as junções ordenadas predominantes. Uma "chave" em data.table é literalmente apenas a ordem de classificação (semelhante a um índice em cluster no SQL; ou seja, é assim que os dados são ordenados na RAM). Na lista é adicionar chaves secundárias, por exemplo.

Em resumo, a diferença de velocidade evidente destacada por esse teste específico de coluna de dois caracteres com mais de 10.000 strings exclusivas não deve ser tão ruim agora, já que o problema conhecido foi corrigido.

Matt Dowle
fonte
6
Se você fornecer um caso de teste para um conjunto de dados realista razoavelmente grande, ficarei feliz em executar os benchmarks. Você é mais que bem-vindo também. Na verdade, ainda não otimizei o código para o caso da chave de junção de número inteiro (coloque isso na minha lista de tarefas!), Mas você pode esperar um desempenho significativamente melhor do que o caso da string, dado o estudo da tabela de hash na apresentação vinculada.
precisa saber é o seguinte
22
Não uso nenhuma dessas bibliotecas, mas estou satisfeito por ver uma resposta construtiva do lado R na forma de Matthew Dowle.
SlowLearner 26/01
3
Aqui estão alguns resultados da Rprof pastie.org/3258362 . Parece que 20-40% do tempo é gasto em correspondência classificada, dependendo do tipo de associação. Vai ter que olhar para colunas inteiras outro I tempo-- fez uma pandas questão GitHub para me lembrar de otimizar nesse caso ( github.com/wesm/pandas/issues/682 )
Wes McKinney
14
As melhorias do @AndyHayden foram feitas há algum tempo. Vou editar nos itens da NEWS. Wes escolheu um teste específico (equi juntando duas colunas de caracteres) que tocou nesse problema conhecido. Se ele tivesse escolhido colunas inteiras, teria sido diferente. E se ele tivesse me avisado antes de apresentar a referência na conferência, eu poderia ter lhe contado mais sobre o problema conhecido.
precisa saber é o seguinte
191

A razão pela qual o pandas é mais rápido é porque eu criei um algoritmo melhor, que é implementado com muito cuidado usando uma implementação rápida de tabela de hash - klib e em C / Cython para evitar a sobrecarga do interpretador Python para as partes não vetorizáveis. O algoritmo é descrito com mais detalhes na minha apresentação: Um olhar sobre o design e desenvolvimento de pandas .

A comparação com data.table é realmente um pouco interessante, porque o ponto principal dos R's data.tableé que ele contém índices pré-calculados para várias colunas para acelerar operações como seleção e mesclagem de dados. Nesse caso (o banco de dados se junta), o DataFrame do pandas não contém informações pré-calculadas que estão sendo usadas para a mesclagem, por assim dizer, é uma mesclagem "fria". Se eu tivesse armazenado as versões fatoradas das chaves de junção, a junção seria significativamente mais rápida - pois fatorar é o maior gargalo desse algoritmo.

Devo acrescentar também que o design interno do DataFrame dos pandas é muito mais acessível a esses tipos de operações que o data.frame do R (que é apenas uma lista de matrizes internamente).

Wes McKinney
fonte
76
Claro, agora que você já entendeu tudo em python, ele deve ser fácil de traduzir para R;)
Hadley
37
Mas por que alguém iria querer? :)
ely
9
Umm ... talvez porque eles gostariam que as operações de dados fossem mais rápidas em R? Apenas adivinhar :))
lebatsnok
28
Oi Wes-- parece que seus resultados data.tableforam direcionados principalmente por um bug que foi corrigido desde então. Alguma chance de você executar novamente seu benchmark e escrever uma postagem de blog atualizada?
Zach
6
Zach certifique-se de verificar isso: github.com/Rdatatable/data.table/wiki/Benchmarks-:-Grouping
Merik
37

Este tópico tem dois anos, mas parece um local provável para as pessoas pousarem quando pesquisam comparações de Pandas e dados.

Como ambos evoluíram ao longo do tempo, quero postar uma comparação relativamente mais recente (de 2014) aqui para os usuários interessados: https://github.com/Rdatatable/data.table/wiki/Benchmarks-:-Grouping

Seria interessante saber se Wes e / ou Matt (que, a propósito, são criadores de Pandas e data.table, respectivamente, e ambos comentaram acima), têm alguma novidade a acrescentar aqui também.

- ATUALIZAÇÃO -

Um comentário postado abaixo por jangorecki contém um link que eu acho muito útil: https://github.com/szilard/benchm-databases

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

Este gráfico mostra os tempos médios de agregação e operações de junção para diferentes tecnologias ( menor = mais rápido ; comparação atualizada pela última vez em setembro de 2016). Foi realmente educativo para mim.

Voltando à pergunta, R DT keye R DTreferem-se aos introduzidos sabores / não codificadas de R de data.table e acontecer de ser mais rápido neste benchmark de Pandas do Python ( Py pandas).

Merik
fonte
1
Eu estava para publicar isto! Obrigado por adicionar.
Zach
7
@Zach veja isso: github.com/szilard/benchm-databases e isso também é legal: speakerdeck.com/szilard/…
jangorecki
1
@Zach, quatro anos depois, novos resultados de benchmark finalmente surgiram, veja minha resposta abaixo.
Jangorecki
7

Existem ótimas respostas, especialmente feitas pelos autores das duas ferramentas sobre as quais a pergunta é feita. A resposta de Matt explica o caso relatado na pergunta, que foi causado por um bug e não por um algoritmo de mesclagem. O bug foi corrigido no dia seguinte, há mais de 7 anos.

Na minha resposta, fornecerei alguns horários atualizados da operação de mesclagem para data.table e pandas. Observe que a mesclagem de plyr e base R não está incluída.

Os horários que estou apresentando são provenientes do projeto db-benchmark , um benchmark reproduzível executado continuamente. Atualiza as ferramentas para versões recentes e executa novamente os scripts de benchmark. Ele roda muitas outras soluções de software. Se você está interessado no Spark, o Dask e alguns outros não se esqueça de verificar o link.


A partir de agora ... (ainda a ser implementado: mais um tamanho de dados e mais 5 perguntas)

Testamos 2 tamanhos de dados diferentes da tabela LHS.
Para cada um desses tamanhos de dados, executamos 5 perguntas de mesclagem diferentes.

q1: junção interna LHS RHS- pequena no número inteiro
q2: junção interna LHS-média RHS no número inteiro
q3: junção externa LHS -média RHS no número inteiro
q4: junção interna LHS-média RHS no fator (categórico)
q5: junção interna LHS-RHS- grande no inteiro

A tabela RHS é de 3 tamanhos diferentes

  • small traduz para o tamanho de LHS / 1e6
  • médio se traduz no tamanho de LHS / 1e3
  • big traduz para o tamanho do LHS

Em todos os casos, existem cerca de 90% das linhas correspondentes entre o LHS e o RHS e não há duplicatas na coluna de junção do RHS (nenhum produto cartesiano).


A partir de agora (executado em 2 de novembro de 2019)

pandas 0.25.3 lançado em 1 de novembro de 2019
data.table 0.12.7 (92abb70) lançado em 2 de novembro de 2019

Os intervalos abaixo estão em segundos, para dois tamanhos de dados diferentes do LHS. Coluna pd2dté adicionada uma taxa de armazenamento de quantas vezes o panda é mais lento que o data.table.

  • Dados LHS de 0,5 GB
+-----------+--------------+----------+--------+
| 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 |
+-----------+--------------+----------+--------+
  • Dados LHS de 5 GB
+-----------+--------------+----------+--------+
| 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 |
+-----------+--------------+----------+--------+
jangorecki
fonte
Obrigado pela atualização do futuro! Você poderia adicionar uma coluna para a implementação R vs python do data.table?
Zach
1
Eu acho que é bom apenas ir ao site e verificá-lo, mesmo olhando para R dt vs pandas. E pyDT realmente não fazia parte da pergunta original.
jangorecki