私が試していることを行うための標準的な方法を探しましたが、早くてエレガントな作業を少ししかしていないようです。要するに、私は複数の値の列を持つ大きなテーブルを持っており、それぞれにルックアップテーブルの対応する要素を乗算したい。ルックアップ値を乗算したい列を動的に渡す方法や、基本的な式の外でルックアップ値を参照する方法を理解できません。高速のdata.table検索でグループごとに複数の列を割り当てます
これは私の例ですが、10の値の列を持つ300万行を設定しましたが、これはあまり時間がかかりすぎず、データサイズを多少表しています(これはもっと大きなループの一部として実装されます)したがって、パフォーマンスに重点を置いています)。 6つのレベルのルックアップテーブルと、value_1のvalue_10カラムに対応するいくつかの揃えられた乗数もあります。
library(data.table)
setsize <- 3000000
value_num <- 10
factors <- c("factor_a", "factor_b", "factor_c", "factor_d", "factor_e", "factor_f")
random <- data.table(replicate(10, sample(factors, size = setsize, replace = T))
, replicate(10, rnorm(setsize, mean = 700, sd = 50)))
lookup <- data.table("V1" = factors, replicate(10, seq(.90, 1.5, length.out = length(factors))))
wps <- paste("value", c(1:10), sep = "_")
names(random)[11:20] <- wps
names(lookup)[2:11] <- wps
setkeyv(random, "V1")
setkeyv(lookup, "V1")
解決方法1:それはかなり速いですが、私は一般的にi.value_1
のようなI-列を参照する方法を見つけ出すことができないので、私はループにそれらを渡すことができますかいっそ一度にすべてを適用します。
f <- function() {
random[lookup, value_1 := value_1 * i.value_1, by = .EACHI]
random[lookup, value_2 := value_2 * i.value_2, by = .EACHI]
random[lookup, value_3 := value_3 * i.value_3, by = .EACHI]
random[lookup, value_4 := value_4 * i.value_4, by = .EACHI]
random[lookup, value_5 := value_5 * i.value_5, by = .EACHI]
random[lookup, value_6 := value_6 * i.value_6, by = .EACHI]
random[lookup, value_7 := value_7 * i.value_7, by = .EACHI]
random[lookup, value_8 := value_8 * i.value_8, by = .EACHI]
random[lookup, value_9 := value_9 * i.value_9, by = .EACHI]
random[lookup, value_10 := value_10 * i.value_10, by = .EACHI]
}
system.time(f())
user system elapsed
0.184 0.000 0.181
解決策2:私は解決策1は一般的なことを得ることができなかった後、私はset()
ベースのアプローチを試してみました。しかし、私が文字列wps
の目標値列を指定できるようにしたにもかかわらず、それは実際には上記よりはるかに遅いです。私はそれを間違って使用していることを知っているが、すべての[.data.tableオーバーヘッドを削除するために改善する方法がわからない。
idx_groups <- random[,.(rowstart = min(.I), rowend = max(.I)), by = key(random)][lookup]
system.time(
for (i in 1:nrow(idx_groups)){
rows <- idx_groups[["rowstart"]][i]:idx_groups[["rowend"]][i]
for (j in wps) {
set(random, i=rows, j=j, value= random[rows][[j]] * idx_groups[[j]][i])
}
})
user system elapsed
3.940 0.024 3.967
これらの操作をよりうまく構成する方法についてのアドバイスをいただければ幸いです。
編集:私はこの質問を投稿する前に、この明白な解決策を試して失敗のために自分で非常にイライラしてる:
system.time(
for (col in wps){
random[lookup, (col) := list(get(col) * get(paste0("i.", col))), by = .EACHI, with = F]
})
user system elapsed
1.600 0.048 1.652
私は相対速度でやりたいようです。しかし、それはまだ上記の最初のソリューション(私は確信しているので、get()
を繰り返している)よりも10倍遅いので、私はまだアドバイスを受けています。
編集2:get()
をeval(parse(text=col))
に置き換えると、このトリックが完了したようです。
system.time(
for (col in wps){
random[lookup, (col) := list(eval(parse(text=col)) * eval(parse(text=paste0("i.", col)))), by = .EACHI, with = F]
})
user system elapsed
0.184 0.000 0.185
編集3:いくつかの良い回答が提供されています。ラファエルのソリューションはおそらく一般的なケースでは最高ですが、私はJangoreckiが推奨するコール構築から数ミリ秒も短く絞ったヘルパー機能と引き換えに絞ることができます。私はそれを返事としてマークしました、皆の助けをありがとう。
私が代わりに ''はeval(パース(...)のmget'を使用して推測します) 'は同じ結果を達成するはずです(しかしテストしませんでした)。あなた自身があなたの質問に答えていれば、正しい解決策を「回答」(編集ではなく)として投稿してください。 THX :-) –
この質問は役に立ちます:https://stackoverflow.com/questions/30468455/dynamically-build-call-for-lookup-multiple-columns-そこから最新のソリューションを試すことができます'get'の構文解析フィールドと実体化フィールドを避けるため、最も効率的です。現在提供されているより速く/より良い解決策を見つけたら、自問自答してください。 – jangorecki
Rヨーダ、残念ながら 'mget'は' eval(parse(...)) 'のように私にとってはうまくいきません。ジャンゴレッキー、リンクありがとう!私はあなたの最後の解決策が私が見たことが最も速いと思います。そして、J表現を検査する能力は、何が起こっているかについてもう少し直観的になります。私はこの質問の答えとして私のバージョンを掲示します。 – etrippler