data.tablesのX [Y]結合が完全外部結合または左結合を許可しないのはなぜですか?


123

これは、data.table結合構文についての哲学的な質問です。data.tablesの用途はますます増えていますが、まだ学習中です...

X[Y]data.tables の結合フォーマットは非常に簡潔で、便利で効率的ですが、私が知る限り、内部結合と右外部結合のみをサポートしています。左または完全な外部結合を取得するには、以下を使用する必要がありますmerge

  • X[Y, nomatch = NA] -Yのすべての行-右外部結合(デフォルト)
  • X[Y, nomatch = 0] -XとYの両方に一致する行のみ-内部結合
  • merge(X, Y, all = TRUE) -XとYの両方からのすべての行-完全外部結合
  • merge(X, Y, all.x = TRUE) -Xのすべての行-左外部結合

X[Y]結合フォーマットが4種類の結合すべてをサポートしていると便利だと思います。2種類の結合のみがサポートされる理由はありますか?

私にとって、nomatch = 0およびnomatch = NAパラメータの値は、実行されるアクションのための非常に直感的ではありません。merge構文を理解して覚える方が簡単です:all = TRUEall.x = TRUEおよびall.y = TRUEX[Y]操作はにmerge非常に似ているので、関数のパラメーターではなく結合matchmerge構文を使用してみませんか?matchnomatch

4つの結合タイプのコード例を以下に示します。

# 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

更新:data.table v1.9.6にon=構文が導入されました。これにより、主キー以外のフィールドでのアドホック結合が可能になります。jangoreckiの質問の回答データフレームを結合(マージ)する方法(内側、外側、左、右)?は、data.tableが処理できる追加の結合タイプの例をいくつか示しています。


4
FAQ 1.12を読みましたか?左外部結合が必要な場合、および完全外部結合が必要な場合はY[X]、いつでも呼び出すことができますX[Y]rbind(Y[X],X[Y])
mnel

完全な外部結合へのdata.tableアプローチの詳細については、私の回答を参照してください
mnel

@ mnel、rbindにはテーブルのコピーが含まunique()れるため、完全な結合については、以下のアプローチがに望ましいとrbind(Y[X],X[Y])思います。そうですか?
ダグラスクラーク

はい、私の知る限りです。3つの小さな一意の呼び出しが1つの大きな呼び出しよりも速いかどうかはテストしていません(たとえばunique(c(unique(X[,t]), unique(Y[,t]))、XとYの行数以下になる2つのリストを組み合わせるだけなので、これはよりメモリ効率が良いはずです) 。
mnel

2
あなたの質問はとても良い説明です。あなたの質問に私の質問への答えを見つけました。ありがとう
irriss

回答:


71

引用するdata.table との違いは何ですかよくある質問1.11 X[Y]merge(X, Y)

X[Y] 結合であり、Y(またはYのキーがある場合はYのキー)をインデックスとして使用してXの行を検索します。

Y[X] Xを使用してYの行を検索する結合(または、Xがある場合はXのキー)

merge(X,Y)同時に両方の方法を実行します。行の数X[Y]Y[X]列の数は、によって返されるのに対し、通常は、異なるmerge(X,Y)merge(Y,X)同じです。

しかし、要点を逃しています。ほとんどのタスクでは、結合またはマージ後にデータに対して何かを実行する必要があります。データのすべての列をマージし、後でそれらの小さなサブセットのみを使用するのはなぜですか?あなたは提案するかもしれませんが merge(X[,ColsNeeded1],Y[,ColsNeeded2])、それはプログラマがどの列が必要であるかを理解することを必要とします。X[Y,j] data.table内では、これらすべてが1つのステップで行われます。を記述するとX[Y,sum(foo*bar)]、data.tableは自動的にj式を検査して、使用する列を確認します。これらの列のみをサブセット化します。他は無視されます。メモリは、j使用する列に対してのみ作成され、列Yは各グループのコンテキスト内で標準のRリサイクルルールを享受します。fooisがin Xで、bar がin であるとしましょうY(他に20の列も含まれますY)。じゃないX[Y,sum(foo*bar)] 無駄にサブセットを続けてすべてをマージするよりも、プログラミングが速く、実行が速いですか?


の左外部結合が必要な場合 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

完全外部結合が必要な場合

# 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
@mnelに感謝します。FAQ 1.12は、完全結合または左外部結合について言及していません。unique()を使用した完全な外部結合の提案は非常に役立ちます。それはFAQにあるべきです。私はマシューダウレが「自分用に設計し、そのようにしたかった」ことを知っています。(FAQ 1.9)ですがX[Y,all=T]、data.table X [Y]構文内で完全な外部結合を指定するためのエレガントな方法になると思いました 。またはX[Y,all.x=T]、左の結合。なぜそんなにデザインされていないのかしら。ちょっとした考え。
ダグラスクラーク


1
@mnel解決策をありがとう...私の日を作った... :)
Ankit

@mnel実行時にNAに0を代入できる方法はありますX[Y[J(unique_keys)]]か?
アンキット2014

11
何data.tableドキュメントについての私に感動しています...それはとても冗長に、まだとても不可解なままにできるということである
NiuBiBang

24

@mnelの回答は適切なので、その回答を受け入れます。これは単なるフォローアップであり、コメントには長すぎます。

mnelが言うように、左/右外部結合は、スワップYXY[X]-vs- によって取得されX[Y]ます。したがって、その構文では4つの結合タイプのうち3つがサポートされており、2、iiucはサポートされていません。

4番目を追加するのは良い考えのようです。full=TRUEorまたはboth=TRUEor merge=TRUE(最適な引数名がわからない場合)を追加X[Y,j,merge=TRUE]すると、FAQ 1.12のBUTの後の理由から、それが役立つ前に発生しなかったとしましょう。新機能のリクエストが追加され、ここにリンクされました。ありがとう:

FR#2301:merge()のように、X [Y]とY [X]の両方の結合にmerge = TRUE引数を追加します。

最近のバージョンはスピードアップしていますmerge.data.table(たとえば、内部で浅いコピーを取り、キーをより効率的に設定することにより)。そのためmerge()、私たちはX[Y]ユーザーにすべてのオプションを提供し、完全に柔軟にするために、より近く、より近くなるように努めています。両方の長所と短所があります。別の優れた機能リクエストは次のとおりです。

FR#2033:by.xおよびby.yをmerge.data.tableに追加

他にいらっしゃる方は是非お越しください。

質問のこの部分で:

match関数のnomatchパラメータではなく、結合にマージ構文を使用しないのはなぜですか?

ご希望の場合はmerge()、構文とその3つの引数allall.xおよびall.yその後のちょうど代わりのものを使用しますX[Y]。すべてのケースをカバーする必要があると思います。それとも、なぜ議論がシングルnomatchインなの[.data.tableですか?もしそうなら、それはFAQ 2.14を考えると自然に思えた方法にすぎません:「data.tableがベースのA [B]構文に触発された理由をさらに説明できますか?」。しかし、また、nomatch現在0との2つの値のみを取りますNA。これを拡張して、負の値が何かを意味するようにしたり、12を指定したりすると、12番目の行の値を使用してNAを埋めるnomatchことができますdata.table。たとえば、将来的にはベクトルまたはそれ自体をaにすることもできます。

うーん。by-without-byはどのようにmerge = TRUEと相互作用しますか?おそらく、これをdatatable-helpに引き継ぐ必要があります


@Matthewに感謝します。@mnelの答えは素晴らしいですが、私の質問は完全結合または左結合を行う方法ではありませんでしたが、「2種類の結合のみがサポートされている理由はありますか?」だから今はもう少し哲学的です;-)実際には私はマージ構文を好みませんが、人々が慣れ親しんでいる既存のものの上に構築するためのRの伝統があるようです。私はjoin="all", join="all.x", join="all.y" and join="x.and.y"ノートの余白に落書きをしていた。それが良いかどうかはわかりません。
ダグラスクラーク

@DouglasClarkたぶんjoinそのような、良い考え。datatable-helpに投稿したので、見てみましょう。data.table落ち着く時間もあるかもしれません。あなたが持っているバイ無しバイ例えば、まだ、および継承されたスコープに参加
Matt Dowle、2012年

上記のコメントで示したように、joiniがデータテーブルの場合は、にキーワードを追加することをお勧めしますX[Y,j,join=string]。結合に使用できる文字列の値は次のとおりです。1) "all.y"および "right"
Douglas Clark

1
こんにちはマット、data.tableライブラリは素晴らしいです。有難うございます; ただし、結合動作(デフォルトでは右外部結合)はメインのドキュメントで目立つように説明する必要があると思います。これを理解するのに3日かかりました。
ティモシーヘンリー2014年

1
@tucsonここにリンクするためだけに、今#709として提出されています。
Matt Dowle、2014年

17

この「答え」は議論の提案です。私のコメントに示されているように、join[。data.table()にパラメーターを追加して、追加の種類の結合を有効にすることをお勧めしますX[Y,j,join=string]。4種類の通常の結合に加えて、3種類の排他的結合とクロス結合もサポートすることをお勧めします。

joinさまざまな結合タイプの文字列値(およびエイリアス)は、次のように提案されています。

  1. "all.y"および"right"-右結合、現在のdata.tableのデフォルト(nomatch = NA)-Xの一致がないNAを持つすべてのY行。
  2. "both"および"inner" -内部結合(nomatch = 0)-XとYが一致する行のみ。

  3. "all.x"および"left" -左結合-Yが一致しないX、NAのすべての行:

  4. "outer"および"full" -完全外部結合-XおよびYのすべての行、一致しないNA

  5. "only.x"および"not.y"-Y一致がない場合に非結合または反結合がX行を返す

  6. "only.y" そして、"not.x"-非加入、または全くXの一致がない場合、Yの行を返す抗参加
  7. "not.both" -他のテーブルと一致しないX行とY行を返す排他結合、つまり排他的論理和(XOR)
  8. "cross"-Xの各行がYの各行と一致するクロス結合またはデカルト積

デフォルト値はjoin="all.y"、現在のデフォルトに対応しています。

「all」、「all.x」、「all.y」の文字列値は、merge()パラメータに対応しています。「右」、「左」、「内部」、および「外部」の文字列は、SQLユーザーにとってより使いやすいかもしれません。

現在のところ、「両方」と「not.both」の文字列が私の最善の提案ですが、内部結合と排他結合については、誰かがより良い文字列の提案を持っているかもしれません。(「排他的」が正しい用語であるかどうかはわかりませんが、「XOR」結合に適切な用語がある場合は修正してください。)

の使用は結合構文または非結合構文のjoin="not.y"代替で あり、おそらく(私にとっては)より明確ですが、それらが同じかどうかはわかりません(data.tableバージョン1.8.3の新機能)。X[-Y,j]X[!Y,j]

クロス結合は便利な場合がありますが、data.tableパラダイムに適合しない場合があります。


1
議論のためにこれをdatatable-helpに送ってください。
Matt Dowle、2012年

3
1しかし、してくださいいずれかで送信するためのデータテーブル・ヘルプ、またはファイル機能要求。追加してもかまいませんjoinが、トラッカーに追加されない限り、忘れられます。
Matt Dowle

1
しばらくの間SOにログインしていないようです。したがって、これをFR#2301に
Matt Dowle

@MattDowle、この機能の+1。(FR#2301で実行しようとしましたが、アクセス許可が拒否されましたというメッセージが表示されます)。
adilapapaya 2015

@adilapapaya RForgeからGitHubに移動しました。ここで+1してください:github.com/Rdatatable/data.table/issues/614。Arunが問題を移植したため、失われることはありませんでした。
Matt Dowle、2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.