R - Count number of "True" value in matrix columns and assign "False"

Viewed 182

I have a matrix the looks like this:

set.seed(1234)
m <- matrix(round(runif(50,0,4)), ncol=10)
m <- (m>2)
      [,1]  [,2]  [,3]  [,4]  [,5]  [,6]  [,7]  [,8]  [,9] [,10]
[1,] FALSE  TRUE  TRUE  TRUE FALSE  TRUE FALSE  TRUE FALSE FALSE
[2,] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE
[3,] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE
[4,] FALSE  TRUE  TRUE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE
[5,]  TRUE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE  TRUE

For each column, I need to count the number of TRUEs. If the total number of TRUEs per column is lower than 3, then I need each TRUE in that column to become FALSE.

For this example, the expected output would be:

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

My real matrix is much larger (100,000 x 2,000), so the solution needs to be fast.

Any hints on how to get there?

2 Answers

First, finding the columns' counts can be done with `colSums:

colSums(m)
#  [1] 1 2 2 1 0 3 0 3 1 2

Then, just like you're overwriting the m matrix with your m <- m > 2, you can overwrite select columns with a conditional:

m[, colSums(m) < 3] <- FALSE
m
#       [,1]  [,2]  [,3]  [,4]  [,5]  [,6]  [,7]  [,8]  [,9] [,10]
# [1,] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE
# [2,] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
# [3,] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE
# [4,] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE
# [5,] FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE

We can also use apply

m[, apply(m, 2, sum) < 3] <- FALSE

Or using tidyverse

library(dplyr)
m %>% 
   as.data.frame %>% 
   mutate(across(everything(), ~ replace(., sum(.) < 3, FALSE)))
Related