Find a particular line or specific value of a matrix vector in R

Asked

Viewed 1,175 times

2

How to build a function that evaluates if any row of the matrix mat is equal to the vector vec both in the code below:

set.seed(000)
mat <- matrix(rnorm(20),4,5)
vec <- c(1.3297993, -0.9285670,  0.7635935, -0.2992151,  0.4356833)
mat[3,]
vec
mat==vec

Furthermore, how to determine whether at least a value of vec is in mat?

Note: I understand that mat==vec must be the same TRUE, that is to say, mat-vec==0 if mat-vec<tol, where tol = 1e-5.

2 answers

1

As a function below you can compare either the rows or columns of a matrix with a vector, respected a numerical tolerance level. If fun = all you compare all vector elements. If fun = any you check if at least one element of the vector is equal (respected the order):

search_vec <- function(mat, vec, dim = 1, tol = 1e-7, fun = all)
  which(apply(mat, dim, function(x) fun(abs(x - vec) < tol)))

Applying to your case, we seek the vector vec on the matrix lines mat, comparing all elements. The function returns line 3 as a response:

search_vec(mat, vec)
[1] 3

Another case, suppose we change the first value of vec. If you search for all elements equal the answer will be empty.

vec[1] <- 10
search_vec(mat, vec)
integer(0)

But if you ask fun = any, the function checks if at least one element is equal, and the response will be line 3:

search_vec(mat, vec, fun = any)
[1] 3

Another situation, suppose we want to know what line it contains -0.799009249. In that case you can also use fun = any and the answer is line 4:

search_vec(mat, -0.799009249, fun = any)
[1] 4

If you want to fetch columns, switch to dim = 2.

1


The function all.equal gives the result you want. I did not use the mat of your example because my computer, even with the adjusted seed, generates random numbers different than yours. So I created a new matrix with well-defined values.

mat  <- matrix(1:50, ncol=5)
vec1 <- c(1, 2, 3, 4, 5)
vec2 <- c(1, 11, 21, 31, 41)
vec3 <- c(5, 15, 25, 35, 45)

which(apply(mat, 1, function(x) all.equal(x, vec1)) == "TRUE")
integer(0)
which(apply(mat, 1, function(x) all.equal(x, vec2)) == "TRUE")
[1] 1
which(apply(mat, 1, function(x) all.equal(x, vec3)) == "TRUE")
[1] 5

What the function all.equal is to compare two objects in the R to see if they are reasonably equal. The good thing about this function is that it has an argument called tolerance (that I use below) to solve precisely the problem of tolerance that may appear in your simulations.

Using the apply, I can apply the function all.equal to all rows of the matrix, without needing a loop.

Below is a suggested function to play this result:

linha <- function(matriz, vetor){
  aux <- which(apply(matriz, 1, function(matriz) all.equal(matriz, vetor, tolerance=1e-5)) == "TRUE")

  if (length(aux) > 0){
    resposta <- aux
  } else {
    resposta <- "nao existe"
  }

  return(resposta)
}

linha(mat, vec1)
[1] "nao existe"
linha(mat, vec2)
[1] 1
linha(mat, vec3)
[1] 5

To find out if at least one vector element is in the matrix, use a code similar to the one above, but without the function all.equal:

which(apply(mat, 1, function(x) x == vec1))
[1] 1
which(apply(mat, 1, function(x) x == vec2))
[1] 1 2 3 4 5
which(apply(mat, 1, function(x) x == vec3))
[1] 21 22 23 24 25

So you’ll know exactly what positions mat which contain elements of vec.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.