user8645239
user8645239

Reputation:

Turning For Loop Function into Apply Function

In R, for a school project, I am trying to turn a function that uses a for loop to a function that uses the apply function.

My function simulates a Poisson distribution where the person can enter the parameters n, lambda and m. m is the number of simulations. It then outputs the mean of all of the means of the m Poisson simulations and outputs a 2x2 grid of box plots so the user can show multiple plots with different parameter values. It is posted below.

I struggling to figure out how to turn this into a function that uses the apply function. As apply needs a matrix, would I need to already have a matrix m.out for certain parameter values from my for loop function. Also, I am not sure exactly what the function would be using apply. I would want to take the mean of every value in the matrix.

Any help is appreciated.

Venom<-function(n,l,m){
  if(!is.numeric(c(n,l,m))){return("Error non-numeric value entered for at `enter code here`least one parameter")}
    m.out<-NULL
    for(i in 1:m){
      data1<-rpois(n,l)
      m.sim<-mean(data1)
      m.out<-rbind(m.out, m.sim)
    }
    finalmean<-mean(m.out)
    hist(m.out, main=paste("Poisson n=",n))
    return(c(finalmean, m.out))
}
par(mfrow=c(2,2))

Upvotes: 1

Views: 228

Answers (1)

Paul
Paul

Reputation: 9087

Here are a few base R and tidyverse alternatives to the for loop.

set.seed(0)
n = 10
l = 5
m = 20

First, here's your original loop. I replaced rbind with c as m.out is being treated as a vector rather than a matrix.

m.out <- NULL
for(i in 1:m){
  data1 <- rpois(n,l)
  m.sim <- mean(data1)
  m.out <- c(m.out, m.sim)
}
print(m.out)
#  [1] 6.1 5.1 4.9 5.0 5.3 4.4 4.8 5.8 4.7 5.2 5.5 4.6 5.2 5.2 4.4 4.5 5.1 5.7 6.0 4.7

Base R

As you mentioned, apply takes a matrix. However, sapply can use vectors as input and output.

sapply(seq_len(m), function(x) {
  mean(rpois(n, l))
})

Another base R solution is to use replicate which will repeat an expression m times. simplify = T will make it output a vector rather than a list.

replicate(
  m,
  mean(rpois(n, l)),
  simplify = T)

Tidyverse

rerun is purrr's version of replicate. It will produce a list, so we need to unlist the result.

library('tidyverse')
rerun(m, mean(rpois(n, l))) %>%
  unlist

Another way is to use map_dbl which will apply a function to each element in the vector and return a vector of doubles.

map_dbl(seq_len(m), ~mean(rpois(n, l)))

Upvotes: 3

Related Questions