2017-01-12 8 views
1

私は、同じものを測定する行を持つ大きなデータセットを持っています(本質的にノイズで重複します)。私が書いているより大きな関数の一環として、ユーザーは選択した関数(例えば、平均、中央値)でこれらの行を折りたたむことができます。match.funは実際の関数よりも遅いR

私の問題は、関数を直接呼び出すと、match.fun(私が必要とするもの)を使うよりもスピードがはるかに速いことです。 MWE:私のシステムで

require(data.table) 

rows <- 100000 
cols <- 1000 
dat <- data.table(id=sample(LETTERS, rows, replace=TRUE), 
        matrix(rnorm(rows*cols), nrow=rows)) 

aggFn <- "median" 

system.time(dat[, lapply(.SD, median), by=id]) 
system.time(dat[, lapply(.SD, match.fun(aggFn)), by=id]) 

、最後の2行の結果タイミング:これは、大規模なデータセットで劇的になり

user system elapsed 
    1.112 0.027 1.141 
    user system elapsed 
    2.854 0.265 3.121 

を。

最終的には、aggregate()がこれを行うことができます(この動作には苦しんでいないようです)が、データサイズのためdata.tableオブジェクトで作業する必要があります。

+1

理由だけで、その後 'lapply('あなたのループの外 'F = match.fun(aggFn)を行いません。 SD、f) '。 'match.fun'は関数そのものよりも遅いことは明らかです。 'match.fun'のコードを見ると、基本的に' get'が実行され、 'aggFn'が本当に関数であることが保証されています。 'aggFn'が既に関数であることを知っていれば、' match.fun'を使う必要はありません。 – MichaelChirico

+1

これは大規模なデータに対しては非常に劇的になると言いますが、 'rows = 1e3; cols = 1e4'となり、時間の増加率は実際にあなたの例に比べて下がりました...マイケルの提案に加えて、 'e = substitute(lapply(.SD、aggFn)、list(aggFn =" median ")); system.time(dat [、eval(e)、by = id]) '、data.table FAQに記載されています。 – Frank

+1

実際には、match.funを使用しているときにGForceがトリガされないため、実際には速度の差があります。 '?GForce'を参照して、' dat [、lapply(.SD、median)、by = id、verbose = TRUE] 'のような' verbose = TRUE'を使ってクエリを実行してみてください。 ' – Frank

答えて

3

理由は、gforce最適化data.tableがmedianのためです。 options(datatable.verbose=TRUE)と設定すると分かります。詳細は、help("GForce")を参照してください。

あなたが他の機能のために比較した場合、あなたがより多くの同様のタイミング取得:最適化を利用する

fun <- median 
aggFn <- "fun" 
system.time(dat[, lapply(.SD, fun), by=id]) 
system.time(dat[, lapply(.SD, match.fun(aggFn)), by=id]) 

可能な回避策を機能がサポートされるように発生した場合、式を評価されるだろう使用して、例えば、それを構築しますeval(parse())恐ろしい:

dat[, eval(parse(text = sprintf("lapply(.SD, %s)", aggFn))), by=id] 

しかし、あなたはmatch.funが追加されます使用して、小さなセキュリティを失うことになります。あなたはこれを行うことができ、ユーザが選択できる機能のリストを持っている場合は

は:

funs <- list(quote(mean), quote(median)) 
fun <- funs[[1]] #select 
expr <- bquote(lapply(.SD, .(fun))) 
a <- dat[, eval(expr), by=id] 
+0

あなたはparseの代わりにuse substituteを使うことができます。関連リンクreval:https://rawgit.com/wiki/Rdatatable/data.table/vignettes/datatable-faq.html#ok-but-i-dont-know-the-expressions-in-advance.-how-プログラム的にパスしてください。 – Frank

+0

すばらしい答え@Roland。 GForceを学ぶのがうれしく、eval()について完全に忘れてしまった!どちらのソリューションも同じようにうまくいきました。究極のdata.tableステートメントの簡潔さのために2番目のものがわずかに優先されています –

+0

最終目標は何かわかりませんが、この質問も面白いかもしれません:http://stackoverflow.com/questions/ 41376034/r-data-table-functional-programming-metaprogramming-computing-on-the-languag – Triamus

関連する問題