Data.table'ların X [Y] birleşmesi neden tam bir dış birleşime veya bir sol birleşime izin vermiyor?


123

Bu, data.table birleştirme sözdizimi hakkında felsefi bir sorudur. Data.tables için gittikçe daha fazla kullanım buluyorum, ancak hala öğreniyorum ...

X[Y]Data.tables için birleştirme formatı çok kısa, kullanışlı ve verimli, ancak söyleyebileceğim kadarıyla, yalnızca iç birleşimleri ve sağ dış birleşimleri destekliyor. Sol veya tam bir dış birleşim elde etmek için şunu kullanmam gerekiyor merge:

  • X[Y, nomatch = NA] - Y'deki tüm satırlar - sağ dış birleştirme (varsayılan)
  • X[Y, nomatch = 0] - yalnızca hem X hem de Y'de eşleşmeleri olan satırlar - iç birleşim
  • merge(X, Y, all = TRUE) - hem X hem de Y'deki tüm satırlar - tam dış birleştirme
  • merge(X, Y, all.x = TRUE) - X'teki tüm satırlar - sol dış birleştirme

Bana öyle geliyor ki, X[Y]birleştirme formatı 4 tür birleştirmeyi destekleseydi kullanışlı olurdu . Yalnızca iki tür birleştirmenin desteklenmesinin bir nedeni var mı?

Benim için nomatch = 0ve nomatch = NAparametre değerleri, gerçekleştirilen eylemler için pek sezgisel değil. Anlamama ve hatırlamak açısından daha kolaydır merge: sözdizimi all = TRUE, all.x = TRUEve all.y = TRUE. Yana X[Y]operasyon benzer, mergeçok daha fazla match, neden kullanmaz mergeyerine katılır için sözdizimi matchişlevin nomatchparametresi?

İşte 4 birleştirme türünün kod örnekleri:

# 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

Güncelleme: data.table v1.9.6 on=, birincil anahtar dışındaki alanlarda ad hoc birleştirmelere izin veren sözdizimini tanıttı . jangorecki cevabı soruya (birleştirme) veri çerçevelerini (iç, dış, sol, sağ) katılmak için nasıl? data.table'ın işleyebileceği ek birleştirme türü örnekleri sağlar.


4
SSS 1.12'yi okudunuz mu? Her zaman arayabilirsin Y[X]isterseniz sol dış birleşim içinde X[Y]ve rbind(Y[X],X[Y])bir tam dış isterseniz katılma
mnel

Tam dış birleştirme için daha data.table yaklaşımı için cevabımı görün
mnel

@mnel, rbind tablonun kopyalanmasını içereceğinden unique(), tam birleştirme için aşağıdaki yaklaşımınızın tercih edildiğini rbind(Y[X],X[Y])varsayıyorum. Bu doğru mu?
Douglas Clark

bildiğim kadarıyla, evet. Üç küçük benzersiz çağrının bir büyükten daha hızlı olup olmadığını test etmedim (örneğin unique(c(unique(X[,t]), unique(Y[,t]))- bu, yalnızca X ve Y'deki satır sayısından daha az veya ona eşit olacak iki listeyi birleştireceğinden daha verimli bellek olmalıdır. .
mnel

2
Sorunuz çok güzel bir açıklama; Sorunuzda sorularıma cevap buldum. Teşekkürler
irriss

Yanıtlar:


72

SSS'den alıntı yapmak için data.table 1.11 X[Y]ve arasındaki fark nedir merge(X, Y)?

X[Y] bir birleşimdir, dizin olarak Y'yi (veya varsa Y'nin anahtarını) kullanarak X'in satırlarını arar.

Y[X] bir birleşimdir, X kullanarak Y'nin satırlarına bakar (veya varsa X'in anahtarını)

merge(X,Y)aynı anda her iki yolu da yapar. Sıralarının sayısı X[Y]ve Y[X]genellikle satır sayısı tarafından döndürülen, oysa farklı merge(X,Y)ve merge(Y,X)aynıdır.

AMA ana noktayı kaçıran bu. Çoğu görev, bir birleştirme veya birleştirmeden sonra veriler üzerinde bir şeyler yapılmasını gerektirir. Daha sonra yalnızca küçük bir alt kümesini kullanmak için neden tüm veri sütunlarını birleştirelim? Önerebilirsiniz merge(X[,ColsNeeded1],Y[,ColsNeeded2]), ancak bu, programcının hangi sütunların gerekli olduğunu bulmasını gerektirir. X[Y,jin data.table tüm bunları sizin için tek adımda yapar. X[Y,sum(foo*bar)]Data.table yazdığınızda , jhangi sütunları kullandığını görmek için ifadeyi otomatik olarak inceler . Yalnızca bu sütunları alt kümeler; diğerleri görmezden gelinir. Bellek yalnızca kullanılan sütunlar için oluşturulur jve Ysütunlar, her grup bağlamında standart R geri dönüşüm kurallarından yararlanır. Diyelim diyelim fooiçindedir Xve çubuk ise Y(20, diğer sütunlarla birlikte içinde Y). değilX[Y,sum(foo*bar)] her şeyin savurgan bir şekilde bir alt küme ile birleştirilmesinden daha hızlı programlanması ve daha hızlı çalıştırılması?


Sol dış birleşim istiyorsanız X[Y]

le <- Y[X]
mallx <- merge(X, Y, all.x = T)
# the column order is different so change to be the same as `merge`
setcolorder(le, names(mallx))
identical(le, mallx)
# [1] TRUE

Tam bir dış birleşim istiyorsanız

# the unique values for the keys over both data sets
unique_keys <- unique(c(X[,t], Y[,t]))
Y[X[J(unique_keys)]]
##   t  b  a
## 1: 1 NA  1
## 2: 2 NA  4
## 3: 3  9  9
## 4: 4 16 16
## 5: 5 25 NA
## 6: 6 36 NA

# The following will give the same with the column order X,Y
X[Y[J(unique_keys)]]

5
Teşekkürler @mnel. SSS 1.12 tam veya sol dış birleşmeden bahsetmez. Unique () ile tam dış birleştirme öneriniz çok yardımcı olur. Bu SSS'de olmalı. Matthew Dowle'un "kendi kullanımı için tasarladığını ve o şekilde olmasını istediğini" biliyorum. (SSS 1.9), ancak X[Y,all=T]data.table X [Y] sözdizimi içinde tam bir dış birleşimi belirtmenin zarif bir yolu olabileceğini düşündüm . Veya X[Y,all.x=T]sol birleşim için. Neden bu şekilde tasarlanmadığını merak ettim. Sadece bir düşünce.
Douglas Clark

1
@DouglasClark Cevabı ekledim ve 2302 dosyaladınız : mnel'in birleştirme birleştirme sözdizimini SSS'ye ekleyin (zamanlamalarla) . Harika öneriler!
Matt Dowle

1
@mnel teşekkürler çözüm için ... :) ... günümü yapılan
Ankit

@mnel NA'ları icra ederken 0 ile ilişkilendirebilmemizin bir yolu var mı X[Y[J(unique_keys)]]?
Ankit

11
data.table dokümantasyonu hakkında beni etkileyen şey, çok ayrıntılı olmasına rağmen çok şifreli kalabilmesidir ...
NiuBiBang,

24

@ mnel'in cevabı yerinde, bu yüzden bu cevabı kabul edin. Bu sadece bir takip, yorumlar için çok uzun.

Mnel'in dediği gibi, sol / sağ dış birleşim yer değiştirerek elde edilir Yve X: Y[X]-vs- X[Y]. Bu nedenle, 4 birleştirme türünden 3'ü bu sözdiziminde desteklenir, 2, iiuc değil.

Dördüncüyü eklemek iyi bir fikir gibi görünüyor. Diyelim biz eklemek demek full=TRUEya both=TRUEya merge=TRUE(değil emin iyi argüman adı?) Bundan önce, sonra bana öyle geldi olmasaydı X[Y,j,merge=TRUE]sonra ANCAK SSS 1.12 yılında nedenlerle faydalı olacaktır. Yeni özellik isteği şimdi eklendi ve buraya tekrar bağlandı, teşekkürler:

FR # 2301: Merge () 'nin yaptığı gibi hem X [Y] hem de Y [X] için birleştirme = DOĞRU bağımsız değişken ekleyin.

Son sürümler hızlandı merge.data.table(örneğin, anahtarları daha verimli bir şekilde ayarlamak için dahili olarak sığ bir kopya alarak). Bu nedenle , tam esneklik için kullanıcıya tüm seçenekleri yakınlaştırmaya merge()ve X[Y]yakınlaştırmaya çalışıyoruz . Her ikisinin de artıları ve eksileri var. Diğer bir önemli özellik isteği:

FR # 2033: merge.data.table için by.x ve by.y ekleyin

Başkaları varsa, lütfen gelmelerini sağlayın.

Sorudaki bu bölüme göre:

neden eşleşmeler için match işlevinin nomatch parametresi yerine birleştirme sözdizimini kullanmıyorsunuz?

İsterseniz merge()sözdizimi ve 3 argümanları all, all.xve all.ysonra sadece yerine kullanan X[Y]. Tüm davaları kapsaması gerektiğini düşünüyorum. Yoksa tartışmanın neden tek nomatcholduğunu [.data.tablemu demek istedin ? Öyleyse, SSS 2.14'te verilen doğal bir yol: "data.table'ın neden temelde A [B] sözdiziminden ilham aldığını daha fazla açıklayabilir misiniz?". Ancak nomatchşu anda yalnızca iki değer alır 0ve NA. Bu, negatif bir değerin bir anlamı olacak şekilde uzatılabilir veya 12, örneğin NA'ları doldurmak için 12. satırın değerlerini kullanmak anlamına gelir veya nomatchgelecekte bir vektör veya hatta kendisi a olabilir data.table.

Hm. By-without-by , birleştirme ile nasıl etkileşim kurar = DOĞRU? Belki de bunu datatable-help'e götürmeliyiz .


Teşekkürler @Matthew. @ mnel'in cevabı mükemmel, ancak sorum tam veya sol birleştirme nasıl yapılacağı değil, "Yalnızca iki tür birleştirmenin desteklenmesinin bir nedeni var mı?" Yani şimdi biraz daha felsefi ;-) Aslında, birleştirme sözdizimini tercih etmiyorum, ancak insanların aşina olduğu mevcut şeyler üzerine inşa etmek için bir R geleneği var gibi görünüyor. join="all", join="all.x", join="all.y" and join="x.and.y"Notlarımın kenarına bir şeyler karaladım . Daha iyi olup olmadığından emin değilim.
Douglas Clark

@DouglasClark Belki joinböyle, iyi fikir. Datatable-help'e gönderdim, bakalım. Belki de data.tableyerleşmek için biraz zaman ver . Eğer var mı by-olmadan-by henüz örneğin ve kapsamını kalıtsal katılmak ?
Matt Dowle

Yukarıda benim yorum belirtildiği gibi, ben bir ekleme önermek joini datatable olduğunda, anahtar kelimeyi: X[Y,j,join=string]. Birleştirme için olası dize değerlerinin şunlar olması önerilir: 1) "all.y" ve "right" -
Douglas Clark

1
Merhaba Matt, data.table kitaplığı harika; Bunun için teşekkür ederim; birleştirme davranışının (varsayılan olarak sağ dış birleştirme) ana belgelerde belirgin bir şekilde açıklanması gerektiğini düşünüyorum; Bunu anlamam 3 günümü aldı.
Timothée HENRY

1
@tucson Sadece buraya bağlantı vermek için, şimdi 709. sayı olarak dosyalandı .
Matt Dowle

17

Bu "cevap" tartışması için bir öneri: gibi, ben bir eklemenizi öneririz benim yorumum belirtilen joinparametreyi [.data.table () yani katılır Başka türlerde, etkinleştirmek için: X[Y,j,join=string]. 4 tip normal birleşime ek olarak, 3 tür özel birleştirme ve çapraz birleştirmeyi de desteklemenizi öneririm .

joinÇeşitli katılmak türleri için dize değerleri (ve takma ad) olması önerilmektedir:

  1. "all.y"ve "right"- sağ birleşim, mevcut data.table default (nomatch = NA) - X eşleşmesi olmayan NA'lı tüm Y satırları;
  2. "both"ve "inner" - iç birleşim (nomatch = 0) - yalnızca X ve Y'nin eşleştiği satırlar;

  3. "all.x"ve "left" - sol birleşim - Y eşleşmeyen X, NA'lardan gelen tüm satırlar:

  4. "outer"ve "full" - tam dış birleştirme - X ve Y'den gelen tüm satırlar, eşleşmenin olmadığı NA'lar

  5. "only.x"ve "not.y"- katılmama veya birleşme karşıtı, Y eşleşmesinin olmadığı X satırlarını döndürür

  6. "only.y" ve "not.x"- katılmama veya katılmama karşıtı X eşleşmesinin olmadığı Y satırları döndürür
  7. "not.both" - diğer masayla eşleşmeyen X ve Y satırlarını döndüren özel birleştirme, yani bir özel veya (XOR)
  8. "cross"- her X satırının Y'nin her satırıyla eşleştiği çapraz birleştirme veya Kartezyen ürün

Varsayılan değer, join="all.y"mevcut varsayılana karşılık gelen değerdir .

"All", "all.x" ve "all.y" dize değerleri merge()parametrelere karşılık gelir . "Sağ", "sol", "iç" ve "dış" dizeler SQL kullanıcıları için daha uygun olabilir.

"İkisi de" ve "her ikisi de değil" dizeleri şu anda en iyi önerimdir - ancak birisinin içsel birleştirme ve özel birleştirme için daha iyi dizi önerileri olabilir. ("Özel" in doğru terminoloji olup olmadığından emin değilim, "XOR" katılımı için uygun bir terim olup olmadığını düzeltin.)

Öğesinin kullanımı, birleştirme sözdizimi join="not.y"için bir alternatif X[-Y,j]veya X[!Y,j]olmayan sözdizimi ve belki daha net (benim için), ancak aynı olup olmadıklarından emin değilim (data.table sürüm 1.8.3'teki yeni özellik).

Çapraz birleştirme bazen kullanışlı olabilir, ancak data.table paradigmasına uymayabilir.


1
Lütfen bunu tartışma için datatable-help'e gönderin .
Matt Dowle

3
+1 Ancak, lütfen datatable-help'e gönderin veya bir özellik talebinde bulunun . Eklemek sorun değil joinama izleyiciye ulaşmadığı sürece unutulacak.
Matt Dowle

1
Bir süredir SO'da oturum açmadığınızı görüyorum. Bu yüzden bunu FR #
2301'de dosyaladım

@MattDowle, bu özellik için +1. (Bunu FR # 2301 aracılığıyla yapmayı denedim, ancak bir izin reddedildi mesajı alıyorum).
adilapapaya

@adilapapaya RForge'den GitHub'a taşındık. Lütfen buradan + 1'leyin : github.com/Rdatatable/data.table/issues/614 . Arun, kaybolmaması için sorunları çözdü.
Matt Dowle
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.