Reputation: 5464
Pretty simple question.
Is there a way to avoid simplification in
apply()
?
I need to do it because I have an apply
which can sometimes simplify (and it does it) and sometimes not, thus creating different data structures depending on the input, so I want to avoid it altogether.
I need either something similar to SIMPLIFY = FALSE
in mapply()
or a mechanism to control output as the one in vapply()
.
Simple reproducible example:
mimat <- matrix(c(1,2,3,4,5,6), nrow = 2)
mimat2 <- matrix(c(3,2,3,4,5,6), nrow = 2)
apply(mimat, MARGIN = 2, function(x) {
if (is.element(el = 1, x)) return(c(0,1))
else return(c(1,2,3))
})
If the apply()
is applied to mimat
it outputs a list, whereas if it is applied to mimat2
it outputs a matrix.
Upvotes: 5
Views: 1510
Reputation: 4077
R4.1.0 added a simplify
argument to apply()
on 2021-03-06.
With older versions of R, the best option is probably
lapply(seq_len(dim(minat)[2]), YourFunction)
Upvotes: 3
Reputation: 21938
I think for your purpose functions from purrr
package might be more suitable as the output is almost known beforehand. And if they couldn't match the output to the data structure they are supposed to return, they throw and error (or die trying as the documentation put it).
For example map
function always returns a list, whereas its variation map_dbl
, map_lgl
and etc each returns a vector of the indicated type.
There is another function called modify
in this family that preserves the structure of the input data (row numbers and col numbers) and don't alter the data structure, however it is said in the documentation that
Since the transformation can alter the structure of the input; it's your responsibility to ensure that the transformation produces a valid output. For example, if you're modifying a data frame, .f must preserve the length of the input.
In your first example when you apply your anonymous function to mimat
the result has different lengths so it is not possible to return a matrix or a data frame as I can try it with map
to get the same result whereas modify
fails to preserve the data structure of the input:
library(purrr)
map(as.data.frame(mimat), function(x) {
if (is.element(el = 1, x)) return(c(0,1))
else return(c(1,2,3))
})
$V1
[1] 0 1
$V2
[1] 1 2 3
$V3
[1] 1 2 3
modify(as.data.frame(mimat), function(x) {
if (is.element(el = 1, x)) return(c(0,1))
else return(c(1,2,3))
})
> Error in `[[<-.data.frame`(`*tmp*`, i, value = c(1, 2, 3)) :
> replacement has 3 rows, data has 2
But in case of your second matrix mimat2
the output of the function has rows of equal lengths so it is possible to make use of a map
variation called map_dfc
to col bind the output. As the modify
again fails cause the output data structure is different from the output:
map_dfc(as.data.frame(mimat2), function(x) {
if (is.element(el = 1, x)) return(c(0,1))
else return(c(1,2,3))
})
# A tibble: 3 x 3
V1 V2 V3
<dbl> <dbl> <dbl>
1 1 1 1
2 2 2 2
3 3 3 3
modify(as.data.frame(mimat2), function(x) {
if (is.element(el = 1, x)) return(c(0,1))
else return(c(1,2,3))
})
Error in `[[<-.data.frame`(`*tmp*`, i, value = c(1, 2, 3)) :
replacement has 3 rows, data has 2
I had to transform them to data frame as otherwise they are considered as a vector and the function is applied on every element instead of just columns. This brief explanation may not get you to what you wanted but I hope it just serves as an introduction to some other functions with fixed outputs. In a nutshell it only boils down to the function you apply on your data structure that has to transform the data in a way that makes it possible to preserve the data structure.
Upvotes: 0