提高模拟 qbeta 值的 sapply 函数的性能
Improving performance of sapply function that simulates qbeta values
我使用这个应用函数:
set.seed(1)
data<-matrix(runif(1000000,0,1),1000000,2)
sapply(seq(0.0025, 0.9975, by=0.005), function (x) qbeta(x, data$a, data$b))
这可能需要很长时间,因为数据可能有 100 万行。 a 和 b 是唯一的随机值。
如何提高性能?是从每一行中查找参数需要时间,还是只是不可避免?我也试过并行版本,它减少了时间,但仍然很慢。
一些结果(不过我是在 38k 行上做的):
> system.time(matrix(qbeta(rep(seq(0.0025, 0.9975, by=0.005),each=nrow(data)),data$a, data$b),nrow=nrow(data)))
user system elapsed
34.53 0.00 34.53
> system.time(sapply(seq(0.0025, 0.9975, by=0.005), function (x) qbeta(x, data$a, data$b)))
user system elapsed
34.22 0.00 34.21
这是我的并行代码:
steps<-seq(0.0025, 0.9975, by=0.005)
qbeta.func <- function(x, data) {
return(qbeta(x, data$a, data$b) * data$value)
}
cl <- makeCluster(rep("localhost",4), type = "SOCK")
t1 <- Sys.time()
data <- parSapply(cl, steps, qbeta.func, data)#
stopCluster(cl)
#data <- data[1:20,1:20]
您无需使用 sapply
即可获得结果,因为 qbeta
已矢量化。我们重复网格值 nrow(df)
次。最后,您将获得一个 matrix
,其行是 data
对应行的 qbeta
的值。注意:考虑到大量时间,这可能会很慢。不要认为你可以从这里大大加快速度,除非你并行化或使用更强大的 PC。试试看:
res<-matrix(qbeta(rep(seq(0.0025, 0.9975, by=0.005),
each=nrow(data)),data$a, data$b),
nrow=nrow(data))
编辑
这里我做一个简单的并行的例子。我们使用 doParallel
包。我们将 data
data.frame 分成一个块列表,然后我们为每个块调用上面的行。从头开始:
#create the data (just 10000 rows)
set.seed(1)
data<-as.data.frame(matrix(runif(10000,0,1),10000,2,dimnames=list(NULL,letters[1:2])))
#split in 10 1000 rows chunks
dataSplit<-split(data,(seq_len(nrow(data))-1)%/%1000)
#define the function to make the qbeta calculation
qbetaVec<-function(grid,values)
matrix(qbeta(rep(grid,each=nrow(values)),values$a,values$b),nrow=nrow(values))
#define the grid
grid<-seq(0.0025, 0.9975, by=0.005)
#full calculation
system.time(res<-qbetaVec(grid,data))
# user system elapsed
#5.103 0.007 5.115
#now we parallelize
library(doParallel)
#set the number of clusters
cl <- makeCluster(8)
registerDoParallel(cl)
#now the calculation with foreach and dopar
system.time(res2<-foreach(i=1:10) %dopar% qbetaVec(grid,dataSplit[[i]]))
# user system elapsed
# 0.026 0.019 1.404
#now we put all together
res3<-do.call(rbind,res2)
identical(res3,res)
#[1] TRUE
我使用这个应用函数:
set.seed(1)
data<-matrix(runif(1000000,0,1),1000000,2)
sapply(seq(0.0025, 0.9975, by=0.005), function (x) qbeta(x, data$a, data$b))
这可能需要很长时间,因为数据可能有 100 万行。 a 和 b 是唯一的随机值。
如何提高性能?是从每一行中查找参数需要时间,还是只是不可避免?我也试过并行版本,它减少了时间,但仍然很慢。
一些结果(不过我是在 38k 行上做的):
> system.time(matrix(qbeta(rep(seq(0.0025, 0.9975, by=0.005),each=nrow(data)),data$a, data$b),nrow=nrow(data)))
user system elapsed
34.53 0.00 34.53
> system.time(sapply(seq(0.0025, 0.9975, by=0.005), function (x) qbeta(x, data$a, data$b)))
user system elapsed
34.22 0.00 34.21
这是我的并行代码:
steps<-seq(0.0025, 0.9975, by=0.005)
qbeta.func <- function(x, data) {
return(qbeta(x, data$a, data$b) * data$value)
}
cl <- makeCluster(rep("localhost",4), type = "SOCK")
t1 <- Sys.time()
data <- parSapply(cl, steps, qbeta.func, data)#
stopCluster(cl)
#data <- data[1:20,1:20]
您无需使用 sapply
即可获得结果,因为 qbeta
已矢量化。我们重复网格值 nrow(df)
次。最后,您将获得一个 matrix
,其行是 data
对应行的 qbeta
的值。注意:考虑到大量时间,这可能会很慢。不要认为你可以从这里大大加快速度,除非你并行化或使用更强大的 PC。试试看:
res<-matrix(qbeta(rep(seq(0.0025, 0.9975, by=0.005),
each=nrow(data)),data$a, data$b),
nrow=nrow(data))
编辑
这里我做一个简单的并行的例子。我们使用 doParallel
包。我们将 data
data.frame 分成一个块列表,然后我们为每个块调用上面的行。从头开始:
#create the data (just 10000 rows)
set.seed(1)
data<-as.data.frame(matrix(runif(10000,0,1),10000,2,dimnames=list(NULL,letters[1:2])))
#split in 10 1000 rows chunks
dataSplit<-split(data,(seq_len(nrow(data))-1)%/%1000)
#define the function to make the qbeta calculation
qbetaVec<-function(grid,values)
matrix(qbeta(rep(grid,each=nrow(values)),values$a,values$b),nrow=nrow(values))
#define the grid
grid<-seq(0.0025, 0.9975, by=0.005)
#full calculation
system.time(res<-qbetaVec(grid,data))
# user system elapsed
#5.103 0.007 5.115
#now we parallelize
library(doParallel)
#set the number of clusters
cl <- makeCluster(8)
registerDoParallel(cl)
#now the calculation with foreach and dopar
system.time(res2<-foreach(i=1:10) %dopar% qbetaVec(grid,dataSplit[[i]]))
# user system elapsed
# 0.026 0.019 1.404
#now we put all together
res3<-do.call(rbind,res2)
identical(res3,res)
#[1] TRUE