Devo investir meu esforço de aprendizagem para os dados barafustante em R, especificamente entre dplyr
, dtplyr
e data.table
?
Eu uso
dplyr
principalmente, mas quando os dados forem grandes demais para isso, usareidata.table
, o que é uma ocorrência rara. Então agora que adtplyr
v1.0 saiu como uma interfacedata.table
, parece que eu nunca mais preciso me preocupar em usar adata.table
interface novamente.Então, quais são os recursos ou aspectos mais úteis
data.table
que não podem ser usadosdtplyr
no momento e que provavelmente nunca serão feitosdtplyr
?Em seu rosto,
dplyr
com os benefícios dedata.table
faz parecer quedtplyr
vai ultrapassardplyr
. Haverá algum motivo para usardplyr
uma vez quedtplyr
esteja totalmente maduro?
Nota: Não estou perguntando sobre dplyr
vs data.table
(como em data.table vs dplyr: um pode fazer algo bem que o outro não pode ou faz mal? ), Mas, como um é preferido sobre o outro para um problema específico, por que não ' Não dtplyr
seja a ferramenta a ser usada.
fonte
dplyr
que você não pode fazer bemdata.table
? Caso contrário, mudardata.table
para será melhor quedtplyr
.dtplyr
leia - me, 'Algumasdata.table
expressões não têmdplyr
equivalente direto . Por exemplo, não há como expressar junções cruzadas ou rotativasdplyr
. e 'Para corresponder àdplyr
semântica,mutate
() não é modificado no local por padrão. Isso significa que a maioria das expressões envolvidasmutate()
deve fazer uma cópia que não seria necessária se você estivesse usandodata.table
diretamente. ' Existe uma maneira de contornar essa segunda parte, mas considerando a frequência com quemutate
é usada, essa é uma desvantagem bastante grande para os meus olhos.Respostas:
Vou tentar dar meus melhores guias, mas não é fácil, porque é preciso estar familiarizado com todos os dados (data.table), {dplyr}, {dtplyr} e também com a base R. Eu uso o {data.table} e muitos pacotes do {tidy-world} (exceto o {dplyr}). Ame os dois, embora prefira sintaxe de data.table a dplyr. Espero que todos os pacotes do mundo organizado usem {dtplyr} ou {data.table} como back-end sempre que necessário.
Como em qualquer outra tradução (pense em dplyr-to-sparkly / SQL), há coisas que podem ou não podem ser traduzidas, pelo menos por enquanto. Quero dizer, talvez um dia {dtplyr} possa torná-lo 100% traduzido, quem sabe. A lista abaixo não é exaustiva nem 100% correta, pois tentarei responder da melhor maneira possível com base no meu conhecimento sobre tópicos / pacotes / questões / etc.
É importante ressaltar que, para as respostas que não são totalmente precisas, espero que ele ofereça alguns guias sobre quais aspectos do {data.table} você deve prestar atenção e compare-o ao {dtplyr} e descubra as respostas por si mesmo. Não tome essas respostas como garantidas.
E espero que este post possa ser usado como um dos recursos para todos os usuários / criadores de {dplyr}, {data.table} ou {dtplyr} para discussões e colaborações e para tornar o #RStats ainda melhor.
{data.table} não é usado apenas para operações rápidas e com eficiência de memória. Muitas pessoas, inclusive eu, preferem a sintaxe elegante de {data.table}. Ele também inclui outras operações rápidas, como funções de séries temporais, como família de rolamento (ou seja
frollapply
), escrita em C. Ele pode ser usado com qualquer função, incluindo o tidyverse. Eu uso muito {data.table} + {purrr}!Complexidade das operações
Isso pode ser facilmente traduzido
{data.table} é muito rápido e economiza memória porque (quase?) tudo é construído desde o início, a partir de C, com os principais conceitos de atualização por referência , chave (pense em SQL) e sua otimização implacável em todos os lugares do pacote (ou seja
fifelse
,fread/fread
ordem de classificação radix adotada pela base R), ao mesmo tempo em que a sintaxe é concisa e consistente, é por isso que acho elegante.Da Introdução à tabela de dados, as principais operações de manipulação de dados, como subconjunto, grupo, atualização, associação, etc., são mantidas juntas por
sintaxe concisa e consistente ...
executando análise fluidamente sem a carga cognitiva de ter que mapear cada operação ...
otimizando automaticamente as operações internamente e com muita eficiência, conhecendo com precisão os dados necessários para cada operação, resultando em códigos muito rápidos e com eficiência de memória
O último ponto, como exemplo,
Dado que, para colher os benefícios de {data.table}, a tradução de {dtplr} deve estar correta nesse aspecto. Quanto mais complexas as operações, mais difíceis as traduções. Para operações simples como acima, certamente pode ser facilmente traduzido. Para os complexos, ou aqueles não suportados pelo {dtplyr}, você deve descobrir a si mesmo como mencionado acima, é preciso comparar a sintaxe e o benchmark traduzidos e ser pacotes relacionados familiares.
Para operações complexas ou não suportadas, posso fornecer alguns exemplos abaixo. Mais uma vez, estou apenas tentando o meu melhor. Seja gentil comigo.
Atualização por referência
Não vou entrar na introdução / detalhes, mas aqui estão alguns links
Recurso principal: Semântica de Referência
Mais detalhes: Entendendo exatamente quando uma data.table é uma referência a (contra uma cópia de) outra data.table
Atualizar por referência , na minha opinião, o recurso mais importante do {data.table} e é isso que o torna tão rápido e eficiente em termos de memória.
dplyr::mutate
não suporta por padrão. Como não estou familiarizado com o {dtplyr}, não tenho certeza de quanto e quais operações podem ou não ser suportadas pelo {dtplyr}. Como mencionado acima, também depende da complexidade das operações, que por sua vez afetam as traduções.Existem duas maneiras de usar a atualização por referência em {data.table}
operador de atribuição de {data.table}
:=
set
-family:set
,setnames
,setcolorder
,setkey
,setDT
,fsetdiff
, e muitos mais:=
é mais comumente usado em comparação comset
. Para conjuntos de dados complexos e grandes, a atualização por referência é a chave para obter velocidade máxima e eficiência de memória. A maneira mais fácil de pensar (não 100% precisa, pois os detalhes são muito mais complicados do que isso, pois envolve cópia impressa / superficial e muitos outros fatores), digamos que você esteja lidando com grandes conjuntos de dados de 10 GB, com 10 colunas e 1 GB cada . Para manipular uma coluna, você precisa lidar apenas com 1 GB.O ponto principal é que, com a atualização por referência , você só precisa lidar com os dados necessários. É por isso que ao usar {data.table}, especialmente ao lidar com grandes conjuntos de dados, usamos atualização por referência o tempo todo, sempre que possível. Por exemplo, manipulando grandes conjuntos de dados de modelagem
A operação de aninhamento
list(.SD)
pode não ser suportada por {dtlyr}, como os usuários usam em ordemtidyr::nest
? Portanto, não tenho certeza se as operações subseqüentes podem ser traduzidas da maneira que o {data.table} é mais rápido e menos memória.NOTA: o resultado do data.table está em "milissegundo", dplyr em "minuto"
Existem muitos casos de uso de atualização por referência e até os usuários do {data.table} não usam a versão avançada o tempo todo, pois exigem mais códigos. Se o {dtplyr} suporta esses itens prontos, você precisa descobrir a si mesmo.
Múltipla atualização por referência para as mesmas funções
Recurso principal: atribuir elegantemente várias colunas em data.table com lapply ()
Isso envolve o mais comumente usado
:=
ouset
.De acordo com o criador de {data.table} Matt Dowle
Join + setkey + atualização por referência
Eu precisava de junção rápida com dados relativamente grandes e padrões de junção semelhantes recentemente, então uso o poder da atualização por referência , em vez de junções normais. Como eles exigem mais códigos, envolvo-os em um pacote privado com avaliação não padrão para reutilização e legibilidade, onde eu chamo
setjoin
.Eu fiz algumas referências aqui: data.table join + update-by-reference + setkey
Sumário
NOTA:
dplyr::left_join
também foi testado e é o mais lento com ~ 9.000 ms, usa mais memória do que os {data.table}update_by_reference
esetkey_n_update
, mas usa menos memória que o normal_join de {data.table}. Ele consumiu cerca de 2,0 GB de memória. Não o incluí, pois quero me concentrar apenas em {data.table}.Principais conclusões
setkey + update
eupdate
são ~ 11 e ~ 6,5 vezes mais rápidos quenormal join
, respectivamentesetkey + update
é semelhante aoupdate
overhead desetkey
compensar amplamente seus próprios ganhos de desempenhosetkey
não é necessário,setkey + update
é mais rápido queupdate
~ 1,8 vezes (ou mais rápido quenormal join
~ 11 vezes)Exemplos
Para junções eficientes em desempenho e memória, use
update
ousetkey + update
, onde o último for mais rápido, ao custo de mais códigos.Vamos ver alguns pseudo- códigos, por questões de brevidade. As lógicas são as mesmas.
Para uma ou algumas colunas
Para muitas colunas
Wrapper para junções rápidas e eficientes na memória ... muitas delas ... com padrão de junção semelhante, envolva-as como
setjoin
acima - comupdate
- com ou semsetkey
Com
setkey
, o argumentoon
pode ser omitido. Também pode ser incluído para facilitar a leitura, especialmente para colaborar com outras pessoas.Operação em linha grande
set
setkey
)Recurso relacionado: Inclua uma linha por referência no final de um objeto data.table
Resumo da atualização por referência
Esses são apenas alguns casos de uso de atualização por referência . Existem muitos mais.
Como você pode ver, para o uso avançado de lidar com dados grandes, existem muitos casos de uso e técnicas usando atualização por referência para conjuntos de dados grandes. Não é tão fácil de usar no {data.table} e, se o {dtplyr} suporta, você pode descobrir por si mesmo.
Eu me concentro na atualização por referência neste post, pois acho que é o recurso mais poderoso do {data.table} para operações rápidas e com eficiência de memória. Dito isto, existem muitos outros aspectos que também o tornam tão eficiente e acho que não são suportados nativamente pelo {dtplyr}.
Outros aspectos-chave
O que é / não é suportado, também depende da complexidade das operações e se envolve o recurso nativo do data.table, como atualização por referência ou
setkey
. E se o código traduzido é o mais eficiente (aquele que os usuários do data.table escrevem) também é outro fator (ou seja, o código é traduzido, mas é a versão eficiente?). Muitas coisas estão interconectadas.setkey
. Consulte Chaves e subconjunto rápido baseado em pesquisa bináriafrollapply
. funções de rolamento, agregados de rolamento, janela deslizante, média móveli
,j
ouby
operações (você pode usar quase qualquer expressão em lá), eu acho que os mais difíceis as traduções, especialmente quando se combinam com atualização por referência ,setkey
e outra data.table nativa funções comofrollapply
stringr::str_*
funções família versus base R e acho que a base R é mais rápida até certo ponto e as utilizo. O ponto é: não se prenda apenas ao arrumação ou à tabela de dados ou ..., explore outras opções para fazer o trabalho.Muitos desses aspectos estão inter-relacionados com os pontos mencionados acima
complexidade das operações
atualização por referência
Você pode descobrir se o {dtplyr} suporta essas operações, especialmente quando elas são combinadas.
Outro truque útil ao lidar com um conjunto de dados pequeno ou grande, durante a sessão interativa, {data.table} realmente cumpre sua promessa de reduzir a programação e calcular o tempo tremendamente.
Chave de configuração para variável usada repetidamente para velocidade e 'nomes de domínio sobrealimentados' (subconjunto sem especificar o nome da variável).
Se suas operações envolvem apenas operações simples, como no primeiro exemplo, {dtplyr} pode fazer o trabalho. Para os complexos / não suportados, você pode usar este guia para comparar os traduzidos de {dtplyr} com a forma como os usuários experientes de data.table codificariam de maneira rápida e eficiente de memória com a sintaxe elegante do data.table. A tradução não significa que é a maneira mais eficiente, pois pode haver diferentes técnicas para lidar com diferentes casos de grandes dados. Para um conjunto de dados ainda maior, você pode combinar {data.table} com {disk.frame} , {fst} e {drake} e outros pacotes incríveis para obter o melhor dele. Há também uma {big.data.table}, mas ela está inativa no momento.
Espero que ajude a todos. Tenha um bom dia ☺☺
fonte
Junções não equi e junções rolantes vêm à mente. Parece não haver planos para incluir funções equivalentes no dplyr, portanto não há nada para o dtplyr traduzir.
Também há a remodelagem (dcast e derretimento otimizados equivalentes às mesmas funções no reshape2) que também não está no dplyr.
Todas as funções * _if e * _at atualmente não podem ser traduzidas com o dtplyr também, mas estão em andamento.
fonte
Atualizar uma coluna ao ingressar Alguns truques .SD Muitas funções f E Deus sabe o que mais, porque #rdatatable é mais do que apenas uma biblioteca simples e não pode ser resumido com poucas funções
É um ecossistema inteiro por si só
Eu nunca precisei do dplyr desde o dia em que comecei a R. Porque o data.table é tão bom
fonte