Векторизация с использованием семейства применять в R - PullRequest
2 голосов
/ 03 мая 2020

Я работаю с моделью линейной регрессии и хочу рассчитать некоторые показатели производительности вручную. Я разделяю свои данные с помощью перекрестной проверки Leave One Out (LOOCV).

Следующий код R дает мне желаемые результаты, но занимает много времени, так как я использую для l oop с LOOCV.

Есть ли способ быстро переписать мой код, используя, например, применить семейство функций в R?

Набор данных загружен из здесь

wdbc <- read_excel("Folds5x2_pp.xlsx") 
wdbc[] <- lapply(wdbc, scale)

   dim(wdbc)

9568    5

   head(wdbc)

1 -0.629 -0.987  1.82  -0.00952  0.521
2  0.742  0.681  1.14  -0.975   -0.586
3 -1.95  -1.17  -0.185  1.29     2.00 
4  0.162  0.237 -0.508  0.228   -0.462
5 -1.19  -1.32  -0.678  1.60     1.14 
6  0.888  0.404 -0.173 -0.996   -0.627

fitted_value <- rep(0,nrow(wdbc))

for(i in 1:nrow(wdbc)){
test<-wdbc[i,]
training<-wdbc[-i,]
m=lad(PE ~ ., data=training, method="BR")

co.data = coef(m)
x = cbind(1, as.matrix(test[, !(colnames(test) %in% "PE")]))
fitted_value[i] <- x %*% co.data
    }

R2<-(cor(wdbc$PE,fitted_value)^2) 
SAD<-sum(abs(wdbc$PE-fitted_value))

c(round(SAD,2) ,round(R2,2))

ПРИМЕЧАНИЕ 1

Данные, использованные в вопросе, служат только для объяснения, поскольку в моем проекте у меня много наборов данных с большими размерами.

РЕДАКТИРОВАТЬ

Основываясь на ответе @ Domini c van Essen, я использовал следующий код R с использованием функции parSapply из пакета parallel, но это занимает больше времени, чем для l oop.

library(parallel)

mycluster=makeCluster(detectCores()-1) 
wdbc <- read_excel("Folds5x2_pp.xlsx") 
wdbc[] <- lapply(wdbc, scale)
clusterExport(mycluster,c("lad","wdbc")) 

fitted_value = parSapply(mycluster,seq_len(nrow(wdbc)),function(i) {
    for(i in 1:nrow(wdbc)){
    test<-wdbc[i,]
    training<-wdbc[-i,]
    m=lad(PE ~ ., data=training, method="BR")

    co.data = coef(m)
    x = cbind(1, as.matrix(test[, !(colnames(test) %in% "PE")]))
  }
    return (x %*% co.data)
})

ПРИМЕЧАНИЕ 2

У меня 8 ядер, и "PE" является зависимой переменной в моем наборе данных.

1 Ответ

2 голосов
/ 03 мая 2020

Вы можете легко переписать свой l oop, используя sapply вместо for..., хотя, как прокомментировал bzki, это само по себе не ускорит ваш код:

# sapply version:
fitted_value = sapply(seq_len(nrow(wdbc)),function(i) {
    # put all the gubbins in here
    # ...
    return (x %*% co.data)
})

Однако Если на вашем компьютере доступно несколько ядер или, что еще лучше, есть доступ к серверу с множеством процессоров, тогда sapply l oop можно легко распараллелить, используя parSapply из пакета 'parallel', как показано в этом примере:

# slow sapply loop (takes 12s):
data=123
answer = sapply(1:12,function(i) {
    Sys.sleep(1)
    return(data+i)
})
# faster parallel version (takes 4s on my laptop with 4 cores):
library(parallel)
mycluster=makeCluster(detectCores()-1) # leave 1 core available for system 
data=123
clusterExport(mycluster,"data") # specify variable(s) that should be available to parallel function
answer = parSapply(mycluster,1:12,function(i) {
    Sys.sleep(1)
    return(data+i)
})
stopCluster(mycluster)
...