バージョン 1.9.8 (2016 年 11 月 25 日の CRAN) ではdata.table
、非等結合が可能です。
非等自己結合
dta[dta, on = .(date > date), allow.cartesian = TRUE, nomatch = 0L,
.(id, x.date, i.date, i.id, i.var)][
id != i.id][order(id)]
id x.date i.date i.id i.var
1: 1 2 1 2 2
2: 1 2 1 3 3
3: 1 2 1 4 4
4: 1 2 1 5 5
5: 2 2 1 1 1
6: 2 2 1 3 3
7: 2 2 1 4 4
8: 2 2 1 5 5
9: 3 2 1 1 1
10: 3 2 1 2 2
11: 3 2 1 4 4
12: 3 2 1 5 5
13: 4 2 1 1 1
14: 4 2 1 2 2
15: 4 2 1 3 3
16: 4 2 1 5 5
17: 5 2 1 1 1
18: 5 2 1 2 2
19: 5 2 1 3 3
20: 5 2 1 4 4
Arun が指摘したように、一意の日付/ID の数が増えると、組み合わせが爆発的に増加します。したがって、allow.cartesian = TRUE
設定する必要がありました。
残念ながら、、、、< および 2 項演算子のみ>=
が非等価>
結合で使用できますが、 は使用できません。したがって、結合の結果は、後で等価になるようにフィルタリングする必要があります。<=
==
!=
id
基準
OPは、コードをさらに高速化するよう求める独自の回答を投稿しました。Arun の回答には、さまざまな問題サイズのタイミングが含まれています。
そのため、以下のベンチマークは、Arun の測定結果を再現して、これまでに投稿された 3 つの異なるアプローチを比較しようとしています。
library(bench)
library(magrittr)
bm <- press(
n_date = c(2, 10, 50),
n_id = c(5, 10, 50),
{
dt0 <- CJ(date = seq_len(n_date), id = seq_len(n_id))
dt0[, var := .I]
mark(
arun = {
dt <- copy(dt0)
setkey(dt, date, id)
dt[!J(1), {
d.tmp = date-1
id.tmp = id
dt[CJ(1:d.tmp, setdiff(id, id.tmp))]
}, by=list(id, date)] -> arun
},
chameau13 = {
dta <- copy(dt0)
dta[,dta[dta[.I]$id!=dta$id & dta[.I]$date>dta$date],by=list(id,date)]
},
uwe = {
dta <- copy(dt0)
dta[dta, on = .(date > date), allow = TRUE, nomatch = 0L,
.(id = x.id, date = x.date, date.1 = i.date, id.1 = i.id, var = i.var)][
id != id.1]
},
check = my_check
)
}
)
Arun のソリューションは参照によってデータセットを変更するため、すべての実行は新しいコピーから始まります。3 つのソリューションは、列名と行の順序が異なります。そのため、カスタム チェック関数を使用して、結果が同じであることを確認します。
my_check <- function(x, y) {
setnames(x, make.unique(names(x)))
setorder(x, id, date, date.1, id.1)
setnames(y, make.unique(names(y)))
setorder(y, id, date, date.1, id.1)
all.equal(x, y, check.attributes = FALSE) %T>%
{if (!isTRUE(.)) print(.)}
}
ベンチマークのタイミングは、次のように視覚化できます。
ggplot2::autoplot(bm)

非等結合は、すべての問題サイズに対して断然最速の方法ですが、OP の予想に反して、OP 独自のソリューションはほとんど常に最も遅い方法です。