2

データ テーブルの動的なサブセット化に関して質問があります。同様に指定されたスタックオーバーフローに多数のスレッドがあることは知っていますが、残念ながら、それらは私を望ましい解決策に導きませんでした。

サンプルデータセット:

require(data.table)
dt <- data.table(date=c(rep(1,5),rep(2,5)),id=rep(1:5,2),var=c(1:10))

IDごとに、以前のすべての期間の他のすべてのIDのサブセットを見つけたいと思います。サンプル データ セットには、5 つの ID と 2 つの期間があります。期間 2 の ID=5 を見ると、対応するサブセットは ID={1,2,3,4) および日付=1 のサブセットになります。この単純なデータ セットでは、もちろんこれを手動でコーディングできます。

dt[,dt[-.I][date<2],by=id]

ただし、これを自動的に行いたいと思います。私は何かを試しました

dt[,dt[-.I][date < unique(dt$date[.I])],by=id] 

しかし、これは残念ながら機能しません。

有益なコメントをお待ちしております。ありがとう!

4

3 に答える 3

2

これがより速い解決策だと思います:

dta <- data.table(date=c(rep(1,5),rep(2,5)),id=rep(1:5,2),var=c(1:10))
dta[,dta[dta[.I]$id!=dta$id & dta[.I]$date>dta$date],by=list(id,date)]

このコードをさらに高速化する方法についてのコメントは大歓迎です。

于 2013-11-08T17:15:47.460 に答える
0

バージョン 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 独自のソリューションはほとんど常に最も遅い方法です。

于 2018-08-13T05:56:05.980 に答える