Brian Smith
Brian Smith

Reputation: 1353

Get subset of a matrix based on a vector

Let say I have below matrix

Mat = matrix(rnorm(25), 5, 5, dimnames = list(LETTERS[1:5], letters[1:5]))

Now I want to subset this matrix based on below vector as column

Vec = c("a", "c", "x", "b", "y")

Mat[, Vec]

With this I get below error -

Error in Mat[, Vec] : subscript out of bounds

I know this error is by R's design. However I want to make it work, such that the elements corresponding to unknown column names would come as NA

Is there any way to achieve this in R?

Thanks for your time.

Upvotes: 1

Views: 381

Answers (2)

Trusky
Trusky

Reputation: 503

How about using match ?

Mat = matrix(rnorm(25), 5, 5, dimnames = list(LETTERS[1:5], letters[1:5]))      
                                                                                
Vec = c("a", "c", "x", "b", "y")                                                

Mat[, match(Vec, colnames(Mat))] 

Which outputs

> Mat[, match(Vec, colnames(Mat))]                                                                                                         
            a          c <NA>          b <NA>                                                                                               
 A  0.2427570 -0.4060827   NA  0.4698090   NA                                                                                               
 B  1.5994373 -0.5916460   NA -0.4074645   NA                                                                                               
 C  0.2120962 -1.4829029   NA -1.0006933   NA                                                                                               
 D -0.6991751  0.6605346   NA -0.6403174   NA                                                                                               
 E -0.2155225  0.8447741   NA -0.8743710   NA

Upvotes: 1

akrun
akrun

Reputation: 886928

We can use intersect to take into account of the column names that are not present in the matrix but only in the vector

mat2 <- Mat[, intersect(Vec, colnames(Mat))]

-output

mat2
      a          c           b
A  0.28358265  0.4285490 -0.64482025
B  0.04228662 -0.7667130 -0.19550185
C -0.57197755 -1.8296791 -0.76012324
D -0.72591283  0.2336603  0.45026240
E -1.13775762 -1.9874356 -0.02215211

If we need to create new columns

nm1 <- setdiff(Vec, colnames(Mat))
nm2 <- setNames(rep(NA, length(nm1)), nm1)
cbind(mat2, t(nm2)[rep(1, nrow(mat2)),])

An easier option would be

Vec <- letters[1:3]
mat2 <- matrix(NA, nrow(Mat), length(Vec),
    dimnames = list(row.names(Mat), Vec))
v1 <- intersect(colnames(Mat), Vec)
mat2[,v1]  <- Mat[, v1]


mat2
#           a          b           c
#A -0.3811391 -0.7600103 -1.33100900
#B  0.4015464  1.2833597  1.06669817
#C  0.1582268  0.1562223  0.61765738
#D  1.5972361  1.4957370  0.45159383
#E  0.1970359 -0.8246555  0.03037087

Or with the original Vec

Vec = c("a", "c", "x", "b", "y")
mat2 <- matrix(NA, nrow(Mat), length(Vec),
     dimnames = list(row.names(Mat), Vec))
v1 <- intersect(colnames(Mat), Vec)
 mat2[,v1]  <- Mat[, v1]
 mat2
#           a           c  x          b  y
#A -0.3811391 -1.33100900 NA -0.7600103 NA
#B  0.4015464  1.06669817 NA  1.2833597 NA
#C  0.1582268  0.61765738 NA  0.1562223 NA
#D  1.5972361  0.45159383 NA  1.4957370 NA
#E  0.1970359  0.03037087 NA -0.8246555 NA

Upvotes: 0

Related Questions