내가 clunky하다고 생각하면 오래된 자전거 나 오래된 자동차 같은 것이 마음에 떠오르지 만 행을 반복하여 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
나는 "어설픈는"다른 방법 : 우리는 이것에 대한 더 많은 for
루프를 사용하기 시작하고
Doh! column_choice, +1별로 그룹화하는 것이 좋습니다. 'cbind()'를 피하고 시간을 더 줄이는 방법이 있어야합니다. 구현되었을 때 그룹별로': ='에 대한 훌륭한 테스트 케이스. –
그룹별로': ='을 사용하여 멋진 편집. 이상적으로 우리는 효율을 위해'.SD'를 사용하지 않으려합니다 (각 그룹에 필요하지 않은 모든 컬럼으로'.SD'를 저장하는 것을 피하기 위해). 아마도 : myDat [, selected : = myDat [[paste0 (column_choice, "_ data")]] [.I by, = column_choice]'. 이 방법이 효과가 있다면 'myDat' 컬럼의 수가 증가할수록 상당히 빨라야합니다. –