0

I have the following matrix:

      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]    0    0    0    0    0    0    0    0    0     0
 [2,]    0    0    0    0    0    0    0    0    0     0
 [3,]    0    0    0    0    0    0    0    0    0     0
 [4,]    1    1    1    1    0    0    0    0    0     0
 [5,]    1    1    1    1    0    0    0    0    0     0
 [6,]    1    1    1    1    0    0    0    0    0     0
 [7,]    1    1    1    1    0    0    0    0    0     0
 [8,]    1    1    1    1    0    0    0    0    0     0
 [9,]    1    1    1    1    0    0    0    0    0     0
[10,]    1    1    1    1    0    0    0    0    0     0

and I would like to know how to extract the 7x4 dimension of the submatrix with elements equal to 1.

4 Answers4

0

You are effectively asking "how many rows and columns have a one in them"? These questions are answered easiest using apply:

apply(M,1,any)
apply(M,2,any)

will tell you the number of rows and columns respectively which contain anything non-zero.

If testing for non-zero-ness isn't really your problem, replace any with a function that will return TRUE for the desired rows and FALSE otherwise.

If you can't guarantee that the ones form a submatrix (i.e. they aren't in a rectangular formation) then you will need to do some more work than this.

JDL
  • 1,496
  • 10
  • 18
0

You can try:

apply(which(matrix==1, arr.ind = T), 2, function(x) length(unique(x)))
row col 
  7   4 
Roman
  • 17,008
  • 3
  • 36
  • 49
0

You could coerce to a sparse matrix and extract the indices slots:

library(Matrix)
m <- as(M, "TsparseMatrix")
#row dim:
diff(range(m@i)) + 1L
#[[1] 7

#column dim:
diff(range(m@j)) + 1L
#[1] 4

I expect this to be quite efficient and it might be useful to store/treat your matrix as a sparse matrix anyway.

Roland
  • 127,288
  • 10
  • 191
  • 288
0

Similar to JDLs answer, but giving you the sub matrix dimensions directly:

mat <- structure(c(
0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L
), .Dim = c(10L, 10L), .Dimnames = list(NULL, NULL))

dim(mat[apply(mat, 1, any), apply(mat, 2, any)])
#[1] 7 4

This will remove rows and columns containing only zeros. If you want to keep rows and columns containing at least one 1, you could do:

mat[3, 5] <- 2 #just to complicate it a little

f <- function(x) any(x==1) #create a simple function

dim(mat[apply(mat, 1, f), apply(mat, 2, f)])
#[1] 7 4
AkselA
  • 8,153
  • 2
  • 21
  • 34