简体   繁体   中英

In R / writing loop function with external function inside

I want to generate 100 queueing models with queuecomputer https://cran.rstudio.com/web/packages/queuecomputer/queuecomputer.pdf (since the arrival and service times are random I would always get different results) and store a specific value of each of the lists in a separate vector. (queuecomputer always returns a list) for example let

 n_customers <- 50
 arrival_rate <- 1.8
 service_rate <- 1
 arrivals <- cumsum(rexp(n_customers, arrival_rate))
 service <- rexp(n_customers, service_rate)
 queue_obj <- queue_step(arrivals, service, servers = 2)

then I would like to access summary(queue_obj)$mwt for all of the 100 samples and put that value in a new vector.

What I have tried so far but it is not working:

 queuetmp <- function(n) {
  for (i in 1:n) {
 queue[[i]] <- queue_step(cumsum(rexp(50, 1/10)), rexp(50, 1/8), servers = 2)
 mwt[i] <- (summary(queue))[[i]]$mwt
 }
 return (mwt)
}

(since queuecomputer is a really new package many won't be familiar with it but the output is just a typical list)

I think you need to move the index i inside and also define queue and mwt as empty lists first, ie:

library(queuecomputer)
n_customers <- 50
arrival_rate <- 1.8
service_rate <- 1
arrivals <- cumsum(rexp(n_customers, arrival_rate))
service <- rexp(n_customers, service_rate)
queue_obj <- queue_step(arrivals, service, servers = 2)
queue <- list()
mwt <- list()

queuetmp <- function(n) {
  for (i in 1:n) {
    queue[[i]] <- queue_step(cumsum(rexp(50, 1/10)), rexp(50, 1/8), servers = 2)
    mwt[i] <- (summary(queue[[i]]))$mwt
  }
  return (mwt)
}

queuetmp(10)

I appear to get output with a nontrivial answer, if that matches what you were expecting?

Since each iteration of the loop is independent - this is something that could be run in parallel (Note: This particular problem doesn't need to be parallelized because it's so fast anyway).

Here is a very fancy and modern way to do this in R. It uses future , purrr , and furrr (a parallel version of purrr ).

library(furrr)
library(queuecomputer)
library(future)
library(future.apply)
library(purrr)

We now set up system for sequential or parallel computation. The :: just tell R which package to find the function. It's unnecessary here since I already ran library(future) but it's something I like to do to make everything clear. Also it can be important when you want to run things in parallel (see inside queuetmp ), because the parallel R sessions might not have the same libraries loaded.

future::plan("sequential") # change this to "multisession" to run in parallel

n_customers <- 50
arrival_rate <- 1/10
service_rate <- 1/8
n_servers <- 2

We make a function queuetmp that returns the result we want. Notice that there is no looping or replication yet.

# We will put this inside the replicate function. 
queuetmp <- function(
  n_customers, 
  arrival_rate, 
  service_rate, 
  n_servers
  
){
  
  queue_output <- queuecomputer::queue_step(
    cumsum(rexp(n_customers, arrival_rate)), 
    rexp(n_customers, service_rate), 
    servers = n_servers
  )
  
  mwt <- summary(queue_output)$mwt
  
  return(mwt)
}

We make a partial function so we don't need to include the arguments everytime. The !! are called "bang bang". You can look them up.

partial_queue_fun <- purrr::partial(queuetmp, !!n_customers, !!arrival_rate, !!service_rate, !!n_servers)

The "bang bang" forces the variables to be evaluated so their values don't need to be looked up everytime. You can see the argument values (as the actual numbers) here.

partial_queue_fun
## <partialised>
## function (...) 
## queuetmp(50, 0.1, 0.125, 2, ...)

When we don't include the "bang bang" (see below), the numbers aren't saved, just their names, which might be a problem when computing things in parallel.

purrr::partial(queuetmp, n_customers, arrival_rate, service_rate, n_servers)
## <partialised>
## function (...) 
## queuetmp(n_customers, arrival_rate, service_rate, n_servers, 
##    ...)

Running the function is simple, since it is self-contained.

partial_queue_fun()
## [1] 1.723047

Now we put this into the parallel version of replicate.

n <- 100 # number of iterations

future_replicate(n, partial_queue_fun(), future.seed = 1)
## [1] 0.547223629 1.897130628 1.620501737...
# etc.... (93 more numbers)

There's a 100 values in total.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM