1

私はdata.tableいくつかの計算に使用してきましたがj、出力を正しく積み重ねるために、パラメーターの可能な戻り値の型は何ですか? 私data.frameは受け入れられることを知っているので、そうでlistなければなりませんか?私の関数は、それぞれに対して複数の行と複数の列を返しますid。想像してみてください:

dtb <- data.table(id=rep(1:5,20), a=1:100, b=sample(1:100, 100), c=sample(1:100, 100))
f <- function(dt) { return(c(dt$a+1, dt$b+1, dt$c+1))}
dtb[,f(.SD), by=id]

これは明らかに適切に機能しません。これは次のことを行います。

dtb <- data.table(id=rep(1:5,20), a=1:100, b=sample(1:100, 100), c=sample(1:100, 100))
f <- function(dt) { return(data.frame(a=dt$a+1, b=dt$b+1, c=dt$c+1))}
dtb[,f(.SD), by=id]

これらの を構築data.frameすることは、非常に非効率的な方法のように思えます。いくつかの提案は何ですか? を使用するby必要があります。

4

2 に答える 2

3

jコンポーネントへのアプローチはネイティブではありませんdata.table-話す

data.tableの構文については、 data.table wikiを読む価値がありますが、そうではありません(パフォーマンスの観点から、使用data.frameひどいです!)。

この質問を参照することも できます。おそらく、使用方法jと動作方法を理解し始めるでしょうlist

  • data.table(またはそのグループ化されたサブセット)内で評価される式のリストを渡します
  • これらは評価されていない式であり、( currentl)関数は、正しい環境(または、グループサブセット)内でこれらを適切に評価するため[に監視に依存しています。listdata.table.SD

この呼び出しは機能します

    dtb[,list(a = a+1, b = b + 1, c = c+1), by = id]

これもそうです(たまたまへの呼び出しである評価されていない式を渡すlist(...)

library(plyr) # for as.quoted
my_list <- as.quoted(paste('list(',paste(letters[1:3], '=', letters[1:3], '+1',collapse= ','),')'))[[1]]
my_list
## list(a = a + 1, b = b + 1, c = c + 1)
dtb[,eval(my_list), by = id]

lapply(.SD, a_function)の呼び出しをと組み合わせて使用​​する可能性もあり.SDcolsます。.SDcols引数を使用すると、関数を評価する列名の文字列を渡すことができるため、これは機能します

dtb[, lapply(.SD,base::'+',1),by= id, .SDcols = c('a','b','c')]

また

dtb[,lapply(.SD, .Primitive('+'),1), by= id, .SDcols = c('a','b','c')]

data.tableが関数として見つからないため、base::'+'または.Primitive('+')の代わりに呼び出したことに注意してください'+''+'

ベンチマーク

これらのソリューションのベンチマーク

benchmark(
  lstdt=dtb[ , flst(.SD), by=id], 
  dfdt=dtb[ , fdf(.SD), by=id], 
  lapplySD = dtb[, lapply(.SD,base::'+',1),by= id, .SDcols = c('a','b','c')],
  lapplySD2 = dtb[, lapply(.SD,.Primitive('+'),1),by= id, .SDcols = c('a','b','c')]
  just_list = dtb[,list(a = a+1,b=b+1,c=c+1),b=id],
  eval_mylist = dtb[,eval(my_list),b=id],
  replications=10^2

##             test replications elapsed relative user.self 
##  2        dfdt          100    0.36 4.000000      0.34       
##  6 eval_mylist          100    0.09 1.000000      0.10       
##  5   just_list          100    0.11 1.222222      0.10        
##  3    lapplySD          100    0.14 1.555556      0.14  
##  4   lapplySD2          100    0.11      1.1      0.11  
##  1       lstdt          100    0.18 2.000000      0.17
于 2012-08-19T23:42:11.920 に答える
2

c(dt$a+1, dt$b+1, dt$c+1)これを書いたとき、単一のベクトル (と group id 列) を期待していたはずです。代わりにこれを試してください:

dtb <- data.table(id=rep(1:5,20), a=1:100, b=sample(1:100, 100), c=sample(1:100, 100))
f <- function(dt) { return(list(dt$a+1, dt$b+1, dt$c+1))}
dtb[,f(.SD), by=id]

EDIT2 (完全なコードを投稿するときにのみ気付いた以前の編集にエラーがありました)。「安い」という質問に対して: リストの構築が「安い」ことを示すベンチマークの実行を次に示します。

flst <- function(dt) { return(list(dt$a+1, dt$b+1, dt$c+1))}
fdf <- function(dt) { return(data.frame(dt$a+1, dt$b+1, dt$c+1))}
require(rbenchmark)
 benchmark(
    lstdt=dtb[ , flst(.SD), by=id], 
    dfdt=dtb[ , fdf(.SD), by=id], 
    replications=10^2
    )
   test replications elapsed relative user.self sys.self user.child sys.child
2  dfdt          100   0.466  2.89441     0.457    0.010          0         0
1 lstdt          100   0.161  1.00000     0.159    0.003          0         0
于 2012-08-19T06:20:40.660 に答える