Por exemplo (não tenho certeza se é o exemplo mais representativo):
N <- 1e6
d1 <- data.frame(x=sample(N,N), y1=rnorm(N))
d2 <- data.frame(x=sample(N,N), y2=rnorm(N))
Isso é o que eu tenho até agora:
d <- merge(d1,d2)
# 7.6 sec
library(plyr)
d <- join(d1,d2)
# 2.9 sec
library(data.table)
dt1 <- data.table(d1, key="x")
dt2 <- data.table(d2, key="x")
d <- data.frame( dt1[dt2,list(x,y1,y2=dt2$y2)] )
# 4.9 sec
library(sqldf)
sqldf()
sqldf("create index ix1 on d1(x)")
sqldf("create index ix2 on d2(x)")
d <- sqldf("select * from d1 inner join d2 on d1.x=d2.x")
sqldf()
# 17.4 sec
performance
r
join
merge
data.table
surfar de dados
fonte
fonte
Respostas:
A abordagem de correspondência funciona quando há uma chave exclusiva no segundo quadro de dados para cada valor de chave no primeiro. Se houver duplicatas no segundo quadro de dados, as abordagens de correspondência e mesclagem não são as mesmas. O Match é, obviamente, mais rápido, pois não está fazendo tanto. Em particular, nunca procura chaves duplicadas. (continua após o código)
No código sqldf postado na pergunta, pode parecer que os índices foram usados nas duas tabelas, mas, na verdade, eles são colocados em tabelas que foram substituídas antes que o sql select seja executado e isso, em parte, explica por que é tão lento. A ideia do sqldf é que os quadros de dados em sua sessão R constituem o banco de dados, não as tabelas no sqlite. Assim, cada vez que o código se refere a um nome de tabela não qualificado, ele o procurará em seu espaço de trabalho R - não no banco de dados principal do sqlite. Portanto, a instrução select que foi mostrada lê d1 e d2 do espaço de trabalho para o banco de dados principal do sqlite, destruindo aqueles que estavam lá com os índices. Como resultado, ele faz uma junção sem índices. Se você quiser usar as versões de d1 e d2 que estão no banco de dados principal do sqlite, você deve se referir a elas como main.d1 e main. d2 e não como d1 e d2. Além disso, se você está tentando fazê-lo funcionar o mais rápido possível, observe que uma junção simples não pode usar índices em ambas as tabelas, portanto, você pode economizar tempo de criação de um dos índices. No código a seguir, ilustramos esses pontos.
Vale a pena notar que o cálculo preciso pode fazer uma grande diferença em qual pacote é mais rápido. Por exemplo, fazemos uma fusão e uma agregação abaixo. Vemos que os resultados são quase revertidos para os dois. No primeiro exemplo, do mais rápido para o mais lento, obtemos: data.table, plyr, merge e sqldf, enquanto no segundo exemplo sqldf, aggregate, data.table e plyr - quase o inverso do primeiro. No primeiro exemplo, sqldf é 3x mais lento que data.table e no segundo é 200x mais rápido que plyr e 100 vezes mais rápido que data.table. Abaixo, mostramos o código de entrada, os tempos de saída para a fusão e os tempos de saída para o agregado. Também vale a pena notar que sqldf é baseado em um banco de dados e, portanto, pode manipular objetos maiores do que R pode manipular (se você usar o argumento dbname de sqldf) enquanto as outras abordagens são limitadas ao processamento na memória principal. Além disso, ilustramos o sqldf com o sqlite, mas ele também suporta os bancos de dados H2 e PostgreSQL.
Os resultados das duas chamadas de benchmark comparando os cálculos de fusão são:
A saída da chamada de benchmark comparando os cálculos agregados são:
fonte
Os 132 segundos relatados nos resultados de Gabor para
data.table
são, na verdade, funções de base de tempocolMeans
ecbind
(a alocação de memória e cópia induzida pelo uso dessas funções). Existem maneiras boas e ruins de usardata.table
também.Observe que não conheço plyr bem, então verifique com Hadley antes de contar com os
plyr
horários aqui. Observe também quedata.table
incluem o tempo para converterdata.table
e definir a chave, para fareness.Esta resposta foi atualizada desde que respondida originalmente em dezembro de 2010. Os resultados do benchmark anterior estão abaixo. Por favor, veja o histórico de revisão desta resposta para ver o que mudou.
fonte
.Internal
chamadas em pacotes CRAN, consulte a Política de Repositório CRAN .data.table
otimiza automaticamentemean
agora (sem chamar.Internal
internamente).for
loop, isso é bom. Você poderia adicionar mais informações sobre "análise SEM" a esse problema? Por exemplo, estou supondo que SEM = microscópio eletrônico de varredura? Saber mais sobre o aplicativo torna-o mais interessante para nós e nos ajuda a priorizar.Para tarefas simples (valores únicos em ambos os lados da junção), eu uso
match
:É muito mais rápido do que mesclar (na minha máquina, 0.13s a 3.37s).
Meus horários:
merge
: 3.32splyr
: 0.84smatch
: 0.12sfonte
Achei que seria interessante postar um benchmark com dplyr no mix: (tinha um monte de coisas funcionando)
Acabei de adicionar:
e configure os dados para dplyr com uma tabela de dados:
Atualizado: removi data.tableBad e plyr e nada além de RStudio aberto (i7, 16 GB de RAM).
Com data.table 1.9 e dplyr com data frame:
Com data.table 1.9 e dplyr com tabela de dados:
Para consistência, aqui está o original com todos e data.table 1.9 e dplyr usando uma tabela de dados:
Acho que esses dados são muito pequenos para os novos data.table e dplyr :)
Conjunto de dados maior:
Demorou cerca de 10-13 GB de RAM apenas para manter os dados antes de executar o benchmark.
Resultados:
Tentei um bilhão, mas explodiu o aríete. 32 GB resolverá isso sem problemas.
[Edit by Arun] (dotcomken, você poderia executar este código e colar seus resultados de benchmarking? Obrigado).
De acordo com a solicitação de Arun aqui, a saída do que você me forneceu para executar:
Desculpe pela confusão, tarde da noite me pegou.
Usar dplyr com data frame parece ser a maneira menos eficiente de processar resumos. Esses métodos são para comparar a funcionalidade exata de data.table e dplyr com seus métodos de estrutura de dados incluídos? Eu quase preferiria separar isso, pois a maioria dos dados precisará ser limpa antes de group_by ou criar a data.table. Pode ser uma questão de gosto, mas acho que a parte mais importante é a eficiência com que os dados podem ser modelados.
fonte
Usando a função merge e seus parâmetros opcionais:
Inner join: merge (df1, df2) funcionará para esses exemplos porque R une automaticamente os quadros por nomes de variáveis comuns, mas você provavelmente deseja especificar merge (df1, df2, by = "CustomerId") para ter certeza de que estavam combinando apenas nos campos desejados. Você também pode usar os parâmetros by.x e by.y se as variáveis correspondentes tiverem nomes diferentes nos diferentes quadros de dados.
fonte