私が不器用だと思うと、古い自転車や古い車のようなものが気になるだけでなく、行を繰り返してRでやります。だからあなたの質問に投稿したものよりも控えめに見えることが判明しましたが、私はよりベクトル化された方法だと思っています。以下は、あなたが上に投稿したより洗練されたコードより約10倍速い(同じ結果を返す)ようです。
この提案はreshape2
パッケージに依存している:私は物事はもう少し面白くすることが可能にcolumn_choice
として "C" を追加しました
library(data.table)
library(reshape2)
:
dat=data.table(a_data = c(55,56,57,65),
b_data = c(1,2,3,4),c_data=c(1000,1001,1002,1003),
column_choice = c("a", "c", "a", "b"))
は、以下のステップがあり、それらをベンチマークのために準備する関数にラップされています。ここで
myFun<-function(myDat){
# convert data.table to data.frame for melt()ing
dat1<-data.frame(myDat)
# add ID variable to keep track of things
dat1$ID<-seq_len(nrow(dat1))
# melt data - because of this line, it's important to only
# pass those variables that are used to select the appropriate value
# i.e., a_data,b_data,c_data,column_choice
dat2<-melt(dat1,id.vars=c("ID","column_choice"))
# Determine which value to choose: a, b, or c
dat2$chosen<-as.numeric(dat2$column_choice==substr(dat2$variable,
1,1))*dat2$value
# cast the data back into the original form
dat_cast<-dcast(dat2,ID+column_choice~.,
fun.aggregate=sum,value.var="chosen")
# rename the last variable
names(dat_cast)[ncol(dat_cast)]<-"chosen"
# merge data back together and return results as a data.table
datOUT<-merge(dat1,dat_cast,by=c("ID","column_choice"),sort=FALSE)
return(data.table(datOUT[,c(names(myDat),"chosen")]))
}
は機能にパッケージ化ソリューションです:
petesFun<-function(myDat){
datOUT=myDat[, data.table(.SD,
chosen=.SD[[paste0(.SD$column_choice, "_data")]]),
by=1:nrow(myDat)]
datOUT$nrow = NULL
return(datOUT)
}
これははるかにエレガントmyFun
よりも見えます。ただし、ベンチマークの結果には大きな違いがあります。
大きなデータを作成してください。表:
test.df<-data.frame(lapply(dat,rep,100))
test.dat<-data.table(test.df)
とベンチマーク:私は「不格好」は異なる方法で解釈できることを提案する
library(rbenchmark)
benchmark(myRes<-myFun(test.dat),petesRes<-petesFun(test.dat),
replications=25,columns=c("test", "replications", "elapsed", "relative"))
# test replications elapsed relative
# 1 myRes <- myFun(test.dat) 25 0.412 1.00000
# 2 petesRes <- petesFun(test.dat) 25 5.429 13.17718
identical(myRes,petesRes)
# [1] TRUE
:)
Doh! column_choice、+1でグループ化するのは非常にいいです。 'cbind()'を避け、時間をさらに短縮する手段が必要です。実装されている場合、グループごとの ':='に対する素晴らしいテストケース。 –
グループで ':='を使って素敵な編集をしました。理想的には、 '.SD'を効率的に使用することを避けたいと思います(' .SD'に各グループに必要でないすべての列を入れるのを避けるため)。たぶん:myDat [、selected:= myDat [[paste0(column_choice、 "_ data")]] [.I]、by = column_choice] 'それが動作すれば、 'myDat'の列の数が増えるにつれて大幅に高速化するはずです。 –