How can I apply a custom function, with multiple arguments, to return an N x M dataframe without a for loop?
For example:
mat1 <- data.frame(a = 1:5, b = -1)
vec1 <- 100:107
myfcn <- function(x, vals){
ans <- (x + vals[1]) * vals[2]
return(ans)
}
df <- data.frame(matrix(nrow = length(mat1), ncol = length(vec1))) # pre-allocate
for (i in 1:length(vec1)){
for (j in 1:nrow(mat1)){
result <- myfcn(vec1[i], vals = c(mat1$a[j], mat1$b[j]))
df[j,i] <- result
}
}
print(df)
This returns the desired output matrix:
How can I skip the for-loop and use some kind of apply function to get the above output matrix?
I tried sapply(vec1, myfcn, vals = c(mat1$a, mat1$b))
, but it returns this:
And I tried outer(vec1, c(mat1$a, mat1$b), myfcn)
, but it returns this:
First of all, you do not need a double for
loop to populate df
, R is vectorized and you can pass the entire vec1
to the function each time through the loop.
mat1 <- data.frame(a = 1:5, b = -1)
vec1 <- 100:107
myfcn <- function(x, vals){
ans <- (x + vals[1]) * vals[2]
return(ans)
}
df <- as.data.frame(matrix(nrow = length(mat1), ncol = length(vec1))) # pre-allocate
for (j in 1:nrow(mat1)){
result <- myfcn(vec1, vals = c(mat1$a[j], mat1$b[j]))
df[j,] <- result
}
df
#> V1 V2 V3 V4 V5 V6 V7 V8
#> 1 -101 -102 -103 -104 -105 -106 -107 -108
#> 2 -102 -103 -104 -105 -106 -107 -108 -109
#> 3 -103 -104 -105 -106 -107 -108 -109 -110
#> 4 -104 -105 -106 -107 -108 -109 -110 -111
#> 5 -105 -106 -107 -108 -109 -110 -111 -112
Created on 2022-10-10 with reprex v2.0.2
Now with a sapply
loop. You don't even have to pre-allocate space, the loop will do it on its own.
df2 <- t(sapply(1:nrow(mat1), \(j) myfcn(vec1, vals = c(mat1$a[j], mat1$b[j]))))
df2 <- as.data.frame(df2)
identical(df, df2)
#> [1] TRUE
Created on 2022-10-10 with reprex v2.0.2
Note also that if you need a tabular data structure but not specifically a data.frame, then the last as.data.frame
is not needed.