Carl Morgenstern
Carl Morgenstern

Reputation: 49

How to select rows from a matrix in. R

Newbie here, so maybe this problem has an obvious solution:

I have a large matrix with no row or column names. I would like to create a data frame consisting of rows from the matrix where a column has a particular value. The column doesn't have a name and I don't know its position in advance.

Here is a small example:

  S <- matrix(c(1,1,2,3,0,0,-2,0,1,2),5,2) 

which prints as:

        [,1] [,2]
  [1,]    1    0
  [2,]    1   -2
  [3,]    2    0
  [4,]    3    1
  [5,]    0    2

now I want to create a data frame of rows that contain an even entry in some column. This should produce a df with rows 1,2,3,5. In my situation there are 1000 columns so I can't enumerate all the columns. (What I need is a quantifier that ranges across columns)

Upvotes: 1

Views: 1372

Answers (4)

TarJae
TarJae

Reputation: 78907

Update: Thanks to valuable comment of MrFlick:

S %>% rowwise() %>% filter(any(is.even(c_across())))

First answer:

  1. matrix to dataframe
  2. across with created function is.even
  3. filter
library(dplyr)
is.even <- function(v) v %% 2 == 0

S <- data.frame(S)
S %>% mutate(across(everything(), is.even,  .names = "{.col}.{.fn}")) %>%
    filter(X1.1 != FALSE  | X2.1 != FALSE) %>% 
    select(X1, X2)

Output:

  X1 X2
1  1  0
2  1 -2
3  2  0
4  0  2

Upvotes: 3

ThomasIsCoding
ThomasIsCoding

Reputation: 101014

We can do like this

subset(
  as.data.frame(S),
  (V1 * V2) %% 2 == 0
)

which gives

  V1 V2
1  1  0
2  1 -2
3  2  0
5  0  2

If you have many columns, you can use an alternative

subset(
  u <- as.data.frame(S),
  Reduce("*", u) %% 2 == 0
)

Upvotes: 1

akrun
akrun

Reputation: 886928

We can use apply from base R on a logical matrix constructed with %% to create a logical vector that can be used to subset the rows

S[ apply(!(S %% 2), 1, any),]

-ouput

      [,1] [,2]
[1,]    1    0
[2,]    1   -2
[3,]    2    0
[4,]    0    2

Or with collapse for efficiency

library(collapse)
sbt(S, dapply(S, MARGIN = 1, FUN = function(x) any(! x %% 2)))
     [,1] [,2]
[1,]    1    0
[2,]    1   -2
[3,]    2    0
[4,]    0    2

Or use tidyverse

library(dplyr)
as.data.frame(S) %>% 
      filter(if_any(everything(), ~ !(. %% 2) ))
   V1 V2
1  1  0
2  1 -2
3  2  0
4  0  2

Upvotes: 1

MrFlick
MrFlick

Reputation: 206167

You can test for "evenness" by look at the value mod 2 (%% 2) and checking if it's zero. You can perform this action across all rows using rowSums() to check for any TRUE values. So you can do

S[rowSums(S %% 2 ==0)>0, ]
#      [,1] [,2]
# [1,]    1    0
# [2,]    1   -2
# [3,]    2    0
# [4,]    0    2

to get just the rows with an even value.

Upvotes: 2

Related Questions