Giuseppe Petri
Giuseppe Petri

Reputation: 640

When running a function in R using mapply, the output I observe is not why I expected

I want to run a function and extract outputs for objects within the function. The output I am expecting is a dataframe with 5 rows and 5 columns. Instead, I obtain a 1000 rows with 5 columns.

Here is the code with reproducible example:

input.rows3 <- data.frame(pd=c(38, 50, 50, 86, 38),
                          Cl=c(15, 40, 30, 81, 15),
                          va=c(150, 145, 160, 141, 150),
                          co=c(3.0, 4.5, 4.0, 4.8, 1.5))

P <- c(seq(0,184,length.out=1000))

deriv.model <- function(a,b,c,x){
        (a*exp(-((((exp(b)*x))/1000))+c+b))/1000
}

marg.N.resp.function3 <- function(va, co, pd, Cl, P){
        a <-  10000  + 20*Cl
        b <- 2
        c <- (-0.05*pd)
        pr <- co / (va/1000)
        optimalP <- as.data.frame(deriv.model(a,b,c,P)) %>% 
                rename(optimalP = "deriv.model(a, b, c, P)") %>% 
                mutate(diff=abs(optimalP - pr))
        resultP <-cbind(optimalP,P) %>%
                slice(which.min(diff)) %>% 
                select(P)
        newlist <- list(a, b, c, pr, resultP)
        return(newlist)

}

results3 <- as.data.frame(t(mapply(marg.N.resp.function3, 
                                   input.rows3$va, 
                                   input.rows3$co, 
                                   input.rows3$pd,
                                   input.rows3$Cl,
                                   P))) 

results3

My understanding is that the last column of the results3 object should be a single value coming from resultP. However, it looks like I am getting the whole P vector (last column of output) that I am using as input. I am probably doing something wrong with the (m)apply function for which I am not very familiar.

Any hint will be appreciated.

Thanks.

Upvotes: 0

Views: 135

Answers (1)

Brian Fisher
Brian Fisher

Reputation: 1367

By passing P as an argument to mapply you are iterating over it and recycling your shorter variables. Two ways around this depending on how you are planing on putting this to use, you could either take P out of both your argument list and the call to mapply, or you can create a list that repeats P once for each iteration though.

The first approach, change your function definition by removing "P" from the argument list:

library(tidyverse) # for %>%

marg.N.resp.function4 <- function(va, co, pd, Cl){
      a <-  10000  + 20*Cl
      b <- 2
      c <- (-0.05*pd)
      pr <- co / (va/1000)
      optimalP <- as.data.frame(deriv.model(a,b,c,P)) %>% 
            rename(optimalP = "deriv.model(a, b, c, P)") %>% 
            mutate(diff=abs(optimalP - pr))
      resultP <-cbind(optimalP,P) %>%
            slice(which.min(diff)) %>% 
            select(P)
      newlist <- list(a, b, c, pr, resultP)
      return(newlist)

}



results4 <- as.data.frame(t(mapply(marg.N.resp.function4, 
                                   input.rows3$va, 
                                   input.rows3$co, 
                                   input.rows3$pd,
                                   input.rows3$Cl 

                                   ))) 

results4

# V1 V2   V3       V4      V5
# 1 10300  2 -1.9       20       0
# 2 10800  2 -2.5 31.03448       0
# 3 10600  2 -2.5       25       0
# 4 11620  2 -4.3 34.04255       0
# 5 10300  2 -1.9       10 17.4975

This approach depends on P being defined outside of the function. If you are calling with different P vectors you would need to reassign P outside of the function before each run.

The second approach would be more versatile and allow you to use other vectors for P in different runs.

results3 <- as.data.frame(t(mapply(marg.N.resp.function3, 
                                   input.rows3$va, 
                                   input.rows3$co, 
                                   input.rows3$pd,
                                   input.rows3$Cl,
                                   list(rep(P, times = 5))

))) 

results3
# V1 V2   V3       V4      V5
# 1 10300  2 -1.9       20       0
# 2 10800  2 -2.5 31.03448       0
# 3 10600  2 -2.5       25       0
# 4 11620  2 -4.3 34.04255       0
# 5 10300  2 -1.9       10 17.4975

identical(results4, results3)
# [1] TRUE

Upvotes: 1

Related Questions