2015-01-01 1 views
0

큰 데이터 프레임 (~ 700 nx 36000 p)이 있고 R에서 randomForest 분석을 수행 할 계획입니다. 전체 프레임 전송의 런타임 부담으로 인해 randomForest (병렬 컴퓨팅 및 512GB RAM조차도), 많은 독립적 인 실행 (Nruns)에서 randomForest에 데이터 프레임 (~ 5 % p)의 다른 무작위 하위 샘플을 보내고 싶습니다. 작은 데이터 프레임의 경우, 전체 데이터 프레임을 randomForest로 보내고 dim (p, Nruns)와 Nrun에서 생성 된 몇 가지 추가 정보를 포함하는 추가 행을 포함하는 중요 결과 행렬을 반환하는 foreach 루프를 만들었습니다. 그러나 각 run에 대해 randomForest에 데이터 프레임의 다른 하위 샘플을 보내도록 스크립트의 foreach() 구성 요소를 생성하는 데 문제가 있습니다. 서브 샘플링은 두 단계로 구성됩니다 : 행을 먼저 샘플링하여 (이 부분이 작동하는) 균형 잡힌 데이터 세트를 생성하고 (결과 클래스에 대해), 열의 서브 세트를 선택하십시오. 원하는 결과는 여전히 dim (p + 3, Nruns)하지만 각 열에는 해당 열이 나타내는 실행에서 임의로 선택한 변수에 대한 결과 만 포함됩니다 (즉, 해당 실행에 대해 선택되지 않은 변수에 누락 값이 있음). 아래 코드를 사용하여 아래 코드를 제출하면 다음과 같은 오류 메시지가 나타납니다. "전화 기능 결합 오류 : " 코드에서와 같이 임의의 열을 선택한 단계를 제외하면 그러나 밸런싱이 수행되는 단계를 유지하면 오류가 발생하지 않으며 출력이 예상대로 (희미한 (p + 3, Nruns) 및 모든 셀에 0이 아닌 값이 있음). 따라서 문제는 섹션 열 샘플링이 수행되는 코드의 1 : Nruns 각각에 대해 열 (및 행)의 새로운 무작위 하위 샘플링을 수행하는 코드에 대한 해결책을 제안 할 수 있는지 알고 싶습니다.R : randomForest() 호출에서 sample() 프로 시저와 함께 foreach()를 사용합니다.

의견을 보내 주셔서 감사합니다.

########################################################################## 
# CREATE FAKE DATA 
########################################################################## 
FAKEinput <- 
data.frame(A=sample(25:75,20, replace=T), B=sample(1:2,20,replace=T), C=as.factor(sample(0:1,20,replace=T,prob=c(0.3,0.7))), 
    D=sample(200:350,20,replace=T), E=sample(2300:2500,20,replace=T), F=sample(92000:105000,20,replace=T), 
    G=sample(280:475,20,replace=T),H=sample(470:550,20,replace=T),I=sample(2537:2723,20,replace=T), 
    J=sample(2984:4199,20,replace=T),K=sample(222:301,20,replace=T),L=sample(28:53,20,replace=T), 
    M=sample(3:9,20,replace=T),N=sample(0:2,20,replace=T),O=sample(0:5,20,replace=T),P=sample(0:2,20,replace=T), 
    Q=sample(0:2,20,replace=T), R=sample(0:2,20,replace=T), S=sample(0:7,20,replace=T)) 

########################################################################## 
# set FOREST DATASET 
########################################################################## 
forestData <- FAKEinput 

########################################################################## 
# set Outcome 
########################################################################## 
Outcome <- "C" 

########################################################################## 
# set DV 
######################################################################### 
forestDV <- forestData$C 
str(forestDV) #factor 

########################################################################## 
#set up number of runs: 
########################################################################## 
Nruns<-5 

########################################################################## 
#set up ntree 
########################################################################## 
ntree=100 

########################################################################### 
#set up mtry: 
########################################################################### 
mtry=round(sqrt(ncol(forestData))) #4 

########################################################################### 
## CREATE DATASET WITH ONLY THE PREDICTORS (I.E., OMIT OUTCOME). 
########################################################################### 
dropVars <- names(forestData) %in% c(Outcome) 
forestPREDICTORS <- forestData[!dropVars] 

########################################################################### 
#set seed first to replicate the random draw of seeds 
########################################################################### 
set.seed(3456) 

########################################################################### 
# GENERATE Nruns RANDOMSEEDS 
########################################################################### 
randomseed<- sample(1:(length(forestData[,1])),Nruns, replace=TRUE) #16 16 18 8 11 

########################################## 
#Load necessary packages into R's memory 
########################################## 
require(iterators) 
require(foreach) 
require(parallel) 
require(doParallel) 
require(randomForest) 

########################################### 
# Get the number of available logical cores 
########################################### 
cores <- detectCores() 
cores 

########################################### 
# Print info on computer, OS, cores 
########################################### 
print(paste('Processor: ', Sys.getenv('PROCESSOR_IDENTIFIER')), sep='') 
print(paste('OS: ', Sys.getenv('OS')), sep='') 
print(paste('Cores: ', cores, sep='')) 

################################################################################################## 
# Set up new function, called ’ImpOOBerr': 
# 1)write in the set random seed part that uses the same ‘i’ from the ‘foreach’ loops 
# 2) save the importance and summary measures output from the random forest run 
# 3) combine all of the importance scores and OOB error summary results (as columns) into single matrix 
# * other options tried to correct error commented out. 
################################################################################################### 
ImpOOBerr<-function(y,d) { 
set.seed(randomseed[i]) 
out.model<-randomForest(y ~ ., 
    data=d, 
    ntree=ntree, 
    mtry=mtry, 
    nodesize=0.1*nrow(forestData), 
    importance=TRUE, 
    proximity=FALSE) 
# create the frame before filling with values? 
#out<-data.frame(matrix(nrow=ncol(forestPREDICTORS)+3, ncol=Nruns)) 
out<-rbind(importance(out.model, type=1, scale=FALSE), 
    mean(out.model$err.rate[,1]), 
    rbind(t(t(quantile(out.model$err.rate[,1], probs=c(0.025, 0.975)))))) 
#rownames(out) <- c(names(forestPREDICTORS),'meanOOB','oobL95CI', 'oobU95CI') # name all the rows 
# OR name only newly-added rows since randomForest importance output preserves the variable names 
rownames(out)[(nrow(out)-2):nrow(out)]<-c('meanOOB','oobL95CI', 'oobU95CI') 
return(out) 
} 

########################################################################### 
# SET UP THE CLUSTER 
########################################################################### 
#Setup clusters via parallel/DoParallel 
cl.spec <- rep("localhost", 10) 
cl <- makeCluster(cl.spec, type="SOCK") 
registerDoParallel(cl, cores=10) 

########################################################################### 
# Employ foreach to carry out randomForest in parallel 
########################################################################## 
system.time(fakeRF <- foreach(i=1:Nruns, .combine='cbind', .packages='randomForest') 
    %dopar% { #<<change to %do% to see speed difference 

###################################################################################################### 
# FIRST, BALANCE THE DATASET ON OUTCOME CLASS FOR INPUT TO randomForest CLASSIFICATION 
###################################################################################################### 
dat1<-forestData[forestData$C==1,] 
dat0<-forestData[forestData$C==0,] 

#################################################### 
# RESET the seed to make sure it is updating and 
# giving different samples for each run 
#################################################### 
set.seed(randomseed[i]) 

#################################################### 
# OVERSAMPLE FROM SMALLER GROUP TO BALANCE DATASET 
#################################################### 
rands=sample(1:dim(dat0)[1],dim(dat1)[1], replace=TRUE) 
balancedCLASS<-rbind(dat0[rands,],dat1) 

###################################################################################################### 
# NOW DO RANDOM SAMPLES OF THE COLUMNS (VARIABLES) TO CREATE NEW DATA SUBSETS TO SEND TO randomForest 
# AT EACH RUN 
# NOTE: TO TEST SCRIPT WITHOUT COLUMN SAMPLING, COMMENT OUT ALL SCRIPT BETWEEN TWO "#xxxxxxxxx.." ROWS 
# AND UNCOMMENT THE NEXT THREE LINES 
###################################################################################################### 
#forestData<-balancedCLASS 
#forestDV<-balancedCLASS$C 
#forestPREDICTORS <- balancedCLASS[!names(balancedCLASS) %in% c('C')] 

##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 
##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 
#################################################### 
# PULL OUT PREDICTORS (i.e., exclue the outcome) 
# before sampling the columns 
#################################################### 
PREDICTORS <- balancedCLASS[!names(balancedCLASS) %in% c('C')] 

#################################################### 
# from the row-balanced set created above, 
# draw a 5-column subset for each run 
#################################################### 
randsCOL= sample(1:dim(PREDICTORS)[2], 5, replace=FALSE) 

#################################################### 
# BIND OUTCOME VAR BACK ONTO RANDOM COL SET 
#################################################### 
Set_BALrandsCOL <- cbind(balancedCLASS$C, balancedCLASS[,randsCOL]) 

#################################################### 
# FIX OUTCOME NAME (was retained as "balancedCLASS$C") 
#################################################### 
names(Set_BALrandsCOL)[names(Set_BALrandsCOL)=="balancedCLASS$C"] <- "C" 

#################################################### 
# ASSIGN THE OUTCOME OF SAMPLING BACK TO 
# forestData, forestDV and forestPREDICTORS for RF runs 
#################################################### 
forestData<-Set_BALrandsCOL 
forestDV<-Set_BALrandsCOL$C 
forestPREDICTORS <- Set_BALrandsCOL[!names(Set_BALrandsCOL) %in% c('C')] 
##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 
##xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 

############################################################################################# 
# CALL FUNCTION THAT WILL RUN randomForest AND COMBINE THE OUTPUT FROM EACH RUN 
############################################################################################# 
ImpOOBerr(forestDV, forestPREDICTORS) 
}) 

########################## 
# stop the cluster 
########################## 
stopCluster(cl) 

############################################################################################# 
# SAVE THE OUTPUT TO FILE 
############################################################################################# 
save(fakeRF, file="D:/RF/WORKING/fakeRF.rda") 
+0

'i = 1'로 수동으로 시도하면 dim (8,1)의 행렬을 얻고 'i = 2'는 dim (7,1)을 얻습니다. 이것이'ImpOOBerr'의 출력에서 ​​알려진 변형이라면'cbind'는 같은 수의 행을 필요로하기 때문에 다른 결합기가 필요합니다. – r2evans

+0

답변 해 주셔서 감사합니다. – KDA

+0

답변 해 주셔서 감사합니다. ImpOOBerr()은 같은 크기의 행렬을 생성해야하며, 무작위로 cols 샘플을 취하는 스크립트 부분 (예 : "#xxxx"행 사이)을 제외하면 수행됩니다. 랜덤 콜 선택에서의 의도는 각 독립 실행에서 동일한 수의 콜을 선택하는 것이 었습니다. 선택된 #col은 출력 행렬의 #rows를 지정하기 때문에 각 행은 동일한 크기의 행렬을 생성해야합니다. 그러나 무작위 샘플링이므로 선택한 특정 콜은 실행 과정에 따라 달라집니다. ImpOOBerr로 결합되는 행렬의 row.names가 각 실행마다 서로 다르기 때문에 오류가 발생합니까? 제안? – KDA

답변

0

위의 문제가 해결되었습니다. r2evans의 첫 번째 의견은 임의 열 하위 집합 섹션을 수정하도록 허용했습니다. 그런 다음 ImpOOBerr 함수를 수정하여 함수의 출력에 각 실행에서 동일한 수의 관측치 (및 동일한 row.names)를 사용하도록했습니다. 이렇게하면 cbind가 % dopar % 문에서 작동합니다. 의견 및 제안에 감사드립니다.

########################################################################## 
# CREATE FAKE DATA 
########################################################################## 
FAKEinput <- 
data.frame(A=sample(25:75,20, replace=T), B=sample(1:2,20,replace=T), C=as.factor(sample(0:1,20,replace=T,prob=c(0.3,0.7))), 
    D=sample(200:350,20,replace=T), E=sample(2300:2500,20,replace=T), F=sample(92000:105000,20,replace=T), 
    G=sample(280:475,20,replace=T),H=sample(470:550,20,replace=T),I=sample(2537:2723,20,replace=T), 
    J=sample(2984:4199,20,replace=T),K=sample(222:301,20,replace=T),L=sample(28:53,20,replace=T), 
    M=sample(3:9,20,replace=T),N=sample(0:2,20,replace=T),O=sample(0:5,20,replace=T),P=sample(0:2,20,replace=T), 
    Q=sample(0:2,20,replace=T), R=sample(0:2,20,replace=T), S=sample(0:7,20,replace=T)) 

########################################################################## 
# set FOREST DATASET 
########################################################################## 
forestData0 <- FAKEinput 

########################################################################## 
# set Outcome 
########################################################################## 
Outcome <- "C" 

########################################################################## 
# set DV 
######################################################################### 
forestDV0 <- forestData0$C 

########################################################################## 
#set up number of runs: 
########################################################################## 
Nruns<-5 

########################################################################## 
#set up ntree 
########################################################################## 
ntree=100 

########################################################################### 
## CREATE DATASET WITH ONLY THE PREDICTORS (I.E., OMIT OUTCOME). 
########################################################################### 
dropVars <- names(forestData0) %in% c(Outcome) 
forestPREDICTORS0 <- forestData0[!dropVars] 

########################################################################### 
# CREATE single-column dataframe, whichi will be used to send the 
# FULL SET OF PREDICTORS TO ImpOOBerr() OUTPUT MATRIX 
# Automatically-generated column name is unwieldy; change that to Predictor. 
########################################################################### 
VARS <-data.frame(c(names(forestPREDICTORS0),'ZZZmeanOOB','ZZZoobL95CI', 'ZZZoobU95CI')) 
VARS <- rename(VARS, c(c.names.forestPREDICTORS0....ZZZmeanOOB....ZZZoobL95CI....ZZZoobU95CI..="Predictor")) 
row.names(VARS) <- VARS$Predictor 

########################################################################### 
#set seed first to replicate the random draw of seeds 
########################################################################### 
set.seed(3456) 

########################################################################### 
# GENERATE Nruns RANDOMSEEDS 
########################################################################### 
randomseed<- sample(1:Nruns,Nruns, replace=FALSE) 

########################################## 
#Load necessary packages into R's memory 
########################################## 
require(iterators) 
require(foreach) 
require(parallel) 
require(doParallel) 
require(randomForest) 

########################################### 
# Get the number of available logical cores 
########################################### 
cores <- detectCores() 
cores 

########################################### 
# Print info on computer, OS, cores 
########################################### 
print(paste('Processor: ', Sys.getenv('PROCESSOR_IDENTIFIER')), sep='') 
print(paste('OS: ', Sys.getenv('OS')), sep='') 
print(paste('Cores: ', cores, sep='')) 

################################################################################################## 
# SET UP NEW FUNCTION, called ’ImpOOBerr': 
# 1) write in the set random seed part that uses the same ‘i’ from the ‘foreach’ loops 
# 2) save the importance and summary measures output from the random forest run 
# 3) combine all of the importance scores and OOB error summary results (as columns) into single matrix 
# 4) merge the ANNOTS dataset with each 'out' file so that cbind function will work 
# (requires same # of rows and same row.names) 
################################################################################################### 
ImpOOBerr<-function(y,d) { 
set.seed(randomseed[i]) 
out.model<-randomForest(y ~ ., 
    data=d, 
    ntree=ntree, 
    mtry=mtry, 
    nodesize=0.1*nrow(forestData), 
    importance=TRUE, 
    proximity=FALSE) 
out<-rbind(importance(out.model, type=1, scale=FALSE), 
    mean(out.model$err.rate[,1]), 
    rbind(t(t(quantile(out.model$err.rate[,1], probs=c(0.025, 0.975)))))) 
rownames(out)[(nrow(out)-2):nrow(out)]<-c('ZZZmeanOOB','ZZZoobL95CI', 'ZZZoobU95CI') 
out2<- merge(ANNOTS, out, by="row.names", all.x=TRUE) 
row.names(out2) <- out2$Row.names 
out2 <- out2[,-1] 
out2 <- out2[order(row.names(out2)),] 
out3 <- data.frame(out2[,-1,drop=FALSE]) # !!!! THIS WORKS !!! 
return(out3) 
} 

########################################################################### 
# SET UP THE CLUSTER 
########################################################################### 
#Setup clusters via parallel/DoParallel 
cl.spec <- rep("localhost", 30) 
cl <- makeCluster(cl.spec, type="SOCK") 
registerDoParallel(cl, cores=30) 

########################################################################### 
# Employ foreach to carry out randomForest in parallel 
########################################################################## 
system.time(fakeRF <- foreach(i=1:Nruns, .combine='cbind', .packages='randomForest') 
    %dopar% { #<<change to %do% to see speed difference 

###################################################################################################### 
# FIRST, BALANCE THE DATASET ON OUTCOME CLASS FOR INPUT TO randomForest CLASSIFICATION 
###################################################################################################### 
dat1<-forestData[forestData$C==1,] 
dat0<-forestData[forestData$C==0,] 

#################################################### 
# RESET the seed to make sure it is updating and 
# giving different samples for each run 
#################################################### 
set.seed(randomseed[i]) 

#################################################### 
# OVERSAMPLE FROM SMALLER GROUP TO BALANCE DATASET 
#################################################### 
rands=sample(1:dim(dat0)[1],dim(dat1)[1], replace=TRUE) 
balancedCLASS<-rbind(dat0[rands,],dat1) 

###################################################################################################### 
# SELECT RANDOM SAMPLES OF THE COLUMNS (VARIABLES) TO CREATE NEW DATA SUBSETS TO SEND TO randomForest 
# AT EACH RUN 
###################################################################################################### 

################################################################# 
# FROM ROW-BALANCED SET CREATED ABOVE (balancedCLASS), 
# DRAW A 5% COL (5% OF 35365=1768) SUBSET FOR EACH RUN 
# OMIT THE OUTCOME COLUMN (3) FROM THE RANDOM SELECTION 
################################################################# 
randsCOLs= sample(balancedCLASS[,-c(3)], 5, replace=FALSE) 

#################################################### 
# BIND OUTCOME VAR BACK ONTO RANDOM COL SET 
#################################################### 
Set_BALrandsCOL <- cbind(balancedCLASS$C, randsCOLs) 

#################################################### 
# FIX OUTCOME NAME (was retained as "balancedCLASS$C") 
#################################################### 
names(Set_BALrandsCOL)[names(Set_BALrandsCOL)=="balancedCLASS$C"] <- "C" 

#################################################### 
# ASSIGN THE OUTCOME OF SAMPLING BACK TO 
# forestData, forestDV and forestPREDICTORS for RF runs 
#################################################### 
forestData<-Set_BALrandsCOL 
forestDV<-Set_BALrandsCOL$C 
forestPREDICTORS <- Set_BALrandsCOL[!names(Set_BALrandsCOL) %in% c('C')] 

############################################################################################# 
# CALL FUNCTION THAT WILL RUN randomForest AND COMBINE THE OUTPUT FROM EACH RUN 
############################################################################################# 
ImpOOBerr(forestDV, forestPREDICTORS) 
}) 

########################## 
# stop the cluster 
########################## 
stopCluster(cl) 

############################################################################################# 
# SAVE THE OUTPUT TO FILE 
############################################################################################# 
save(fakeRF, file="D:/LearningMachines/RF/Knight_ADNI/WORKING/fakeRF.rda")