1 つの方法は次のとおりです。
require(data.table)
dt <- data.table(sample_data)
# multiple seems to be a character, convert to numeric
dt[, multiple := as.numeric(multiple)]
setkey(dt, "multiple")
dt[J(rep(unique(multiple), unique(multiple))), allow.cartesian=TRUE]
最後の行を除くすべてが単純である必要があります。最後の行では、 を使用してキー列を使用してサブセットを使用していますJ(.)
。対応する値の各値J(.)
は「キー列」と照合され、一致したサブセットが返されます。
つまり、dt[J(1)]
そうすると、サブセットが得られますmultiple = 1
。注意深く注意すると、dt[J(rep(1,2)]
実行すると同じサブセットが 2 回得られます。dt[J(1,1)]
passとには違いがあることに注意してくださいdt[J(rep(1,2)]
。前者は (1,1) の値を data.table の最初の 2 つのキー列とそれぞれ照合しますが、後者は (1 と 2) をデータの最初のキー列と照合してサブセット化します。テーブル。
したがって、列の同じ値を で 2 回渡すと、2 回J(.)
複製されます。このトリックを使用して、1 回 1 回、2 回 2 回などを渡します。それがこのrep(.)
部分の機能です。rep(.)
1,2,2,3,3,3,4,4,4,4 を返します。
max(nrow(dt), nrow(i))
そして、結合の結果が(i は 内にある rep ベクトル)よりも多くの行になる場合、この結合を実行J(.)
するために明示的に使用する必要がありますallow.cartesian = TRUE
(これは data.table 1.8.8 の新機能だと思います)。
編集:これは、「比較的」ビッグデータで行ったベンチマークです。どちらの方法でも、メモリ割り当てにスパイクは見られません。しかし、R の関数内でピーク時のメモリ使用量を監視する方法をまだ見つけていません。SO でそのような投稿を見たことがあると確信していますが、現時点では滑っています。また書きます。現時点では、誰かが興味を持っている/自分で実行したい場合に備えて、テスト データといくつかの予備的な結果を示します。
# dummy data
set.seed(45)
yr <- 1900:2013
sz <- sample(10:50, length(yr), replace = TRUE)
token <- unlist(sapply(sz, function(x) do.call(paste0, data.frame(matrix(sample(letters, x*4, replace=T), ncol=4)))))
multiple <- rep(sample(500:5000, length(yr), replace=TRUE), sz)
DF <- data.frame(yr = rep(yr, sz),
token = token,
multiple = multiple, stringsAsFactors=FALSE)
# Arun's solution
ARUN.DT <- function(dt) {
setkey(dt, "multiple")
idx <- unique(dt$multiple)
dt[J(rep(idx,idx)), allow.cartesian=TRUE]
}
# Ricardo's solution
RICARDO.DT <- function(dt) {
setkey(dt, key="yr")
newDT <- setkey(dt[, rep(NA, list(rows=length(token) * unique(multiple))), by=yr][, list(yr)], 'yr')
newDT[, tokenReps := as.character(NA)]
# Add the rep'd tokens into newDT, using recycling
newDT[, tokenReps := dt[.(y)][, token], by=list(y=yr)]
newDT
}
# create data.table
require(data.table)
DT <- data.table(DF)
# benchmark both versions
require(rbenchmark)
benchmark(res1 <- ARUN.DT(DT), res2 <- RICARDO.DT(DT), replications=10, order="elapsed")
# test replications elapsed relative user.self sys.self
# 1 res1 <- ARUN.DT(DT) 10 9.542 1.000 7.218 1.394
# 2 res2 <- RICARDO.DT(DT) 10 17.484 1.832 14.270 2.888
しかし、Ricardo が言うように、メモリが不足しても問題にならない場合があります。したがって、その場合、速度とメモリの間でトレードオフが必要になります。私が確認したいのは、ここで両方の方法で使用されるピークメモリであり、使用するJoin
方が良いかどうかを明確に言います.