Reputation: 49
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
Reputation: 78907
Update: Thanks to valuable comment of MrFlick:
S %>% rowwise() %>% filter(any(is.even(c_across())))
First answer:
across
with created function is.even
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
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
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
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