Essa é uma pergunta filosófica sobre a sintaxe de junção data.table. Estou encontrando mais e mais usos para data.tables, mas ainda estou aprendendo ...
O formato de junção X[Y]
para data.tables é muito conciso, prático e eficiente, mas, tanto quanto posso dizer, ele suporta apenas junções internas e externas. Para obter uma junção externa esquerda ou total, preciso usar merge
:
X[Y, nomatch = NA]
- todas as linhas em Y - junção externa direita (padrão)X[Y, nomatch = 0]
- apenas linhas com correspondências em X e Y - junção internamerge(X, Y, all = TRUE)
- todas as linhas de X e Y - junção externa completamerge(X, Y, all.x = TRUE)
- todas as linhas em X - junção externa esquerda
Parece-me que seria útil se o X[Y]
formato de junção suportasse todos os 4 tipos de junções. Existe uma razão para apenas dois tipos de junções serem suportados?
Para mim, os valores de parâmetro nomatch = 0
e nomatch = NA
não são muito intuitivos para as ações que estão sendo executadas. É mais fácil para mim compreender e lembrar a merge
sintaxe: all = TRUE
, all.x = TRUE
e all.y = TRUE
. Como a X[Y]
operação se assemelha a merge
muito mais do que match
, por que não usar a merge
sintaxe para junções em vez match
do nomatch
parâmetro da função ?
Aqui estão exemplos de código dos 4 tipos de junção:
# sample X and Y data.tables
library(data.table)
X <- data.table(t = 1:4, a = (1:4)^2)
setkey(X, t)
X
# t a
# 1: 1 1
# 2: 2 4
# 3: 3 9
# 4: 4 16
Y <- data.table(t = 3:6, b = (3:6)^2)
setkey(Y, t)
Y
# t b
# 1: 3 9
# 2: 4 16
# 3: 5 25
# 4: 6 36
# all rows from Y - right outer join
X[Y] # default
# t a b
# 1: 3 9 9
# 2: 4 16 16
# 3: 5 NA 25
# 4: 6 NA 36
X[Y, nomatch = NA] # same as above
# t a b
# 1: 3 9 9
# 2: 4 16 16
# 3: 5 NA 25
# 4: 6 NA 36
merge(X, Y, by = "t", all.y = TRUE) # same as above
# t a b
# 1: 3 9 9
# 2: 4 16 16
# 3: 5 NA 25
# 4: 6 NA 36
identical(X[Y], merge(X, Y, by = "t", all.y = TRUE))
# [1] TRUE
# only rows in both X and Y - inner join
X[Y, nomatch = 0]
# t a b
# 1: 3 9 9
# 2: 4 16 16
merge(X, Y, by = "t") # same as above
# t a b
# 1: 3 9 9
# 2: 4 16 16
merge(X, Y, by = "t", all = FALSE) # same as above
# t a b
# 1: 3 9 9
# 2: 4 16 16
identical( X[Y, nomatch = 0], merge(X, Y, by = "t", all = FALSE) )
# [1] TRUE
# all rows from X - left outer join
merge(X, Y, by = "t", all.x = TRUE)
# t a b
# 1: 1 1 NA
# 2: 2 4 NA
# 3: 3 9 9
# 4: 4 16 16
# all rows from both X and Y - full outer join
merge(X, Y, by = "t", all = TRUE)
# t a b
# 1: 1 1 NA
# 2: 2 4 NA
# 3: 3 9 9
# 4: 4 16 16
# 5: 5 NA 25
# 6: 6 NA 36
Atualização: data.table v1.9.6 introduziu a on=
sintaxe, que permite junções ad hoc em outros campos que não a chave primária. resposta de jangorecki à pergunta Como unir (mesclar) quadros de dados (interno, externo, esquerdo, direito)? fornece alguns exemplos de tipos de junção adicionais que o data.table pode manipular.
fonte
Y[X]
se quiser que a junção externa esquerda doX[Y]
erbind(Y[X],X[Y])
se você quiser uma junção externa completaunique()
abordagem abaixo para a junção completa seja preferívelrbind(Y[X],X[Y])
, uma vez que o rbind envolveria a cópia da tabela. Isso está certo?unique(c(unique(X[,t]), unique(Y[,t]))
- isso deve ser mais eficiente em termos de memória, pois combina apenas duas listas que serão menores ou iguais ao número de linhas em X e Y .Respostas:
Para citar a
data.table
FAQ 1.11 Qual é a diferença entreX[Y]
emerge(X, Y)
?Se você deseja uma junção externa esquerda de
X[Y]
Se você deseja uma junção externa completa
fonte
X[Y,all=T]
poderia ser uma maneira elegante de especificar uma junção externa completa na sintaxe data.table X [Y]. OuX[Y,all.x=T]
para a junção esquerda. Gostaria de saber por que não foi projetado dessa maneira. Apenas um pensamento.X[Y[J(unique_keys)]]
?A resposta do @ mnel é imediata, então aceite essa resposta. Isso é apenas acompanhamento, muito tempo para comentários.
Como mnel diz, a junção externa esquerda / direita é obtida trocando
Y
eX
:Y[X]
-vs-X[Y]
. Portanto, três dos quatro tipos de junção são suportados nessa sintaxe, não em 2, iiuc.Adicionando o quarto parece uma boa idéia. Digamos que adicionemos
full=TRUE
ouboth=TRUE
oumerge=TRUE
(não tenho certeza do melhor nome do argumento?), Então não me ocorreu antes que issoX[Y,j,merge=TRUE]
seria útil pelos motivos após o MAS, na FAQ 1.12. Agora, a solicitação de novos recursos foi adicionada e vinculada aqui, obrigado:FR # 2301: Adicionar argumento de mesclagem = VERDADEIRO para as junções X [Y] e Y [X] como mescla ().
Versões recentes foram aceleradas
merge.data.table
(fazendo uma cópia superficial internamente para definir as chaves com mais eficiência, por exemplo). Portanto, estamos tentando aproximarmerge()
eX[Y]
aproximar e fornecer todas as opções ao usuário para obter total flexibilidade. Existem prós e contras de ambos. Outra solicitação de recurso pendente é:FR # 2033: adicione by.xe by.y para mesclar.data.table
Se houver outros, mantenha-os próximos.
Por esta parte da pergunta:
Se preferir
merge()
sintaxe e seus 3 argumentosall
,all.x
eall.y
depois é só usar que em vez deX[Y]
. Pense que deve cobrir todos os casos. Ou você quis dizer por que é o argumento de um úniconomatch
em[.data.table
? Nesse caso, é exatamente o que parecia natural, dada a FAQ 2.14: "Você pode explicar melhor por que o data.table é inspirado na sintaxe A [B] na base?". Mas tambémnomatch
leva apenas dois valores atualmente0
eNA
. Isso poderia ser estendido para que um valor negativo significasse alguma coisa, ou 12 significaria usar os valores da 12ª linha para preencher NAs, por exemplo, ounomatch
no futuro poderia ser um vetor ou mesmo adata.table
.Hum. Como o by-sem-by interage com merge = TRUE? Talvez devêssemos levar isso para a ajuda de dados .
fonte
join="all", join="all.x", join="all.y" and join="x.and.y"
na margem das minhas anotações. Não tenho certeza se isso é melhor.join
assim, boa ideia. Eu postei na datatable-help, então vamos ver. Talvez dêdata.table
algum tempo para se instalar também. Você já conseguiu passar por sem, por exemplo, e ingressar no escopo herdado ?join
palavra-chave para, quando i é uma tabela de dados:X[Y,j,join=string]
. Os possíveis valores de cadeia para se juntar são sugeridas para ser: 1) "all.y" e "direita" -Esta "resposta" é uma proposta para discussão: Como indicado no meu comentário, sugiro adicionando um
join
parâmetro para [.data.table () para permitir que outros tipos de junta, ou seja:X[Y,j,join=string]
. Além dos 4 tipos de junções comuns, também sugiro oferecer suporte a 3 tipos de junções exclusivas e a junção cruzada .Os
join
valores de sequência (e aliases) para os vários tipos de junção são propostos como:"all.y"
e"right"
- junção direita, o presente padrão data.table (nomatch = NA) - todas as linhas Y com NAs onde não há correspondência X;"both"
e"inner"
- junção interna (nomatch = 0) - apenas linhas onde X e Y correspondem;"all.x"
e"left"
- junção esquerda - todas as linhas de X, NAs onde nenhum Y corresponde:"outer"
e"full"
- junção externa completa - todas as linhas de X e Y, NAs onde não há correspondência"only.x"
e"not.y"
- linhas X retornando não-junção ou anti-junção, onde não há correspondência Y"only.y"
e"not.x"
- linhas Y que retornam sem associação ou anti-associação, onde não há correspondência X"not.both"
- junção exclusiva retornando linhas X e Y onde não há correspondência com a outra tabela, ou seja, um exclusivo ou (XOR)"cross"
- junção cruzada ou produto cartesiano com cada linha de X correspondente a cada linha de YO valor padrão é o
join="all.y"
que corresponde ao padrão atual.Os valores das strings "all", "all.x" e "all.y" correspondem aos
merge()
parâmetros. As cadeias "direita", "esquerda", "interna" e "externa" podem ser mais acessíveis aos usuários do SQL.As strings "both" e "not.both" são minha melhor sugestão no momento - mas alguém pode ter sugestões de strings melhores para a junção interna e exclusiva. (Não tenho certeza se "exclusivo" é a terminologia correta, corrija-me se houver um termo adequado para uma associação "XOR".)
O uso de
join="not.y"
uma alternativa paraX[-Y,j]
ouX[!Y,j]
não participar de sintaxe e talvez mais claro (para mim), embora eu não tenho certeza se eles são os mesmos (recurso novo na versão data.table 1.8.3).Às vezes, a junção cruzada pode ser útil, mas pode não se encaixar no paradigma data.table.
fonte
join
mas, a menos que chegue ao rastreador, será esquecido.