Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a function in R that splits a matrix along a margin using a factor or categorical vector?

Tags:

loops

r

matrix

I am trying to split a matrix in the same way that you might split a data.frame using split. Is there a function that does that? For example, I have matrix m and I am trying to split it into a list of matrices using vector g.

m <- matrix(rnorm(50), ncol = 5)
groups <- c('A', 'B', 'C')
g <- sample(groups, 10, replace = T)

split doesn't seem to work with matrices so we could convert it into a data.frame:

split(data.frame(m), f = g)

This works but I'd like to keep it as a matrix. The following loop works:

lapply(groups, function(x) m[g == x,])

But is there a dedicated function, or a better way?

like image 843
Dan Lewer Avatar asked Feb 03 '26 22:02

Dan Lewer


2 Answers

Here is a way to split a matrix using lapply/split.

lapply(split(m, g), matrix, ncol = ncol(m))

This can easily be written as a one-line function but I prefer a version with some error check.

mat_split <- function(x, f) {
  stopifnot(nrow(x) == length(f))
  lapply(split(x, f), matrix, ncol = ncol(x))
}

Edit

The original question is (my emphasis):

But is there a dedicated function, or a better way?

Following this comment by user20650 there is a function or, better said, a method.

The split.data.frame method can solve the problem.

split.data.frame(m, g)

And this is written in the documentation. From help('split') (my emphasis).

split and split<- are generic functions with default and data.frame methods. The data frame method can also be used to split a matrix into a list of matrices, and the replacement form likewise, provided they are invoked explicitly.

like image 142
Rui Barradas Avatar answered Feb 05 '26 12:02

Rui Barradas


We can split on the sequence of rows of 'm', and use that index to subset the rows of 'm'

lapply(split(seq_len(nrow(m)), g), function(i) m[i,])
like image 44
akrun Avatar answered Feb 05 '26 12:02

akrun



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!