Search code examples
rdataframeloopsvector

Combine output vectors into dataframe


I wrote a function with a vector of length 3 as output which has a structure like this:

func <- function(input){
    a <- 15+input
    b <- 5+input
    c <- -5+input
    return(c(a,b,c)) 
}

and I have input values input <- seq(200,300)

I'd like to call the function 100 times (length(input)), then I'd like to calculate the output vectors for each value in input and I'd like to combine the output vectors into a dataframe.

How can I do this efficiently?

EDIT: I made a mistake. length(input) is 101 in that case.


Solution

  • You can do this with sapply, which gives you a 3x101 matrix, transpose it, then convert it to a data frame. If you want the colnames to be a, b, c then you can set them after:

    sapply(input, func) |> # Apply `func` to every input separately
      t() |> # Transpose
      as.data.frame() # convert to data frame
    

    This gives output:

         V1  V2  V3
    1   215 205 195
    2   216 206 196
    3   217 207 197
    4   218 208 198
    5   219 209 199
    6   220 210 200
    7   221 211 201
    8   222 212 202
    9   223 213 203
    10  224 214 204
    ...
    ...
    ...
    

    Alternatively, if you name your return list with a, b, and c, you can get the names out:

    func <- function(input){
      a <- 15+input
      b <- 5+input
      c <- -5+input
      return( c(a = a,b = b, c = c) ) # Note the names 
    }
    
    sapply(input, func) |>
      t() |>
      as.data.frame()
    
    

    returns

          a   b   c
    1   215 205 195
    2   216 206 196
    3   217 207 197
    4   218 208 198
    5   219 209 199
    6   220 210 200
    7   221 211 201
    8   222 212 202
    9   223 213 203
    10  224 214 204
    ...
    ...
    ...
    

    Finally, you can return a data frame from your function, do an lapply to apply the function to each input then bind all the rows together:

    func <- function(input){
      a <- 15+input
      b <- 5+input
      c <- -5+input
      return(data.frame(a = a, b = b, c = c)) 
    }
    
    lapply(input, func) |>
      do.call(rbind, args = _) 
    
    

    which returns the same as above.