R - return position of element in matrix? - r

Given a matrix:
[,1] [,2]
[1,] 0 0.0
[2,] -1 0.8
What is the quickest way in R to iterate over the matrix and return the position of all non-zero entries as an index?

Here is one approach
mat = matrix(rnorm(9), 3, 3)
which(mat !=0, arr.ind = T)

m <- matrix(c(0, 1, 1, 0), nrow = 2)
which(m != 0)
or maybe
which(m != 0, TRUE)

Related

Sequentially multiply matrices from a list by a vector at time t-1 (recursively)

I am trying to multiply a list of matrices, in the order they appear within the list starting with matrix 1, by an initial vector and then recursively; so matrix 2 from the list multiplied by that resulting vector. I have tried various iteration of lapply and map but am unable to project forward and perform this recursively. More explicitly: A[[1]] % * % allYears[,1], then A[[2]] % * % allYears[,2],.....,A[[4]] % * % allYears[,4] which produces the final 5th column in "allYears". Below is the sample code with the known error in the for loop at A[[i]] indexing as i is not explicitly referenced.
A <- lapply(1:4, function(x) # construct list of matrices
matrix(c(0, 0, 10,
rbeta(1, 5, 4), 0, 0,
0, rbeta(1, 10, 2), 0), nrow=3, ncol=3, byrow=TRUE, ))
n <- c(1000, 100, 10) # initial vector of abundances
nYears <- 4 # define the number of years to project over
allYears <- matrix(0, nrow=3, ncol=nYears+1) # build a storage array for all abundances
allYears[, 1] <- n # set the year 0 abundance
for (t in 1:(nYears + 1)) { # loop through all years
allYears[, t] <- A[[i]] %*% allYears[, t - 1]
}
Based on the description, perhaps we need to loop over the sequence - i.e. length of A is 4, whereas the number of columns of 'allYears' is 5. Create an index from 2 to ncol of 'allYears', then loop over the sequence of that index, extract the corresponding element of 'A' based on the sequence whereas we get the allYears previous column
i1 <- 2:(nYears + 1)
for(t in seq_along(i1)) {
allYears[,i1[t]] <- A[[t]] %*% allYears[,i1[t]-1]
}
-output
> allYears
[,1] [,2] [,3] [,4] [,5]
[1,] 1000 100.00000 817.24277 2081.08322 333.6702
[2,] 100 261.46150 55.44237 423.22095 1244.6680
[3,] 10 81.72428 208.10832 33.36702 355.5175
Alternative, possibly too clever, solution:
Construct a list of (A[[1]], A[[1]] %*% A[[2]], ... )
Alist <- Reduce("%*%", A, accumulate=TRUE)
Multiply each of these by the initial value
vlist <- lapply(Alist, "%*%", n)
Combine:
do.call(cbind, vlist)
[,1] [,2] [,3] [,4]
[1,] 100.00000 856.66558 4864.20044 486.420
[2,] 569.23739 56.92374 543.02451 3307.690
[3,] 78.55101 553.62548 55.36255 445.619
#MikaelJagan points out that this can be done in fewer steps:
do.call(cbind,
rev(Reduce("%*%", rev(A), init = n, right = TRUE, accumulate = TRUE)))
or (in recent versions of R)
(A
|> rev()
|> Reduce(f = "%*%", init = n, right = TRUE, accumulate = TRUE)
|> rev()
|> do.call(what = cbind)
)
(The last step could be replaced by |> unlist() |> matrix(nrow = length(n)).)

R: find indexes of vector in another vector (if it exists)

I would like to know the starting index of a vector in another vector. For example, for c(1, 1) and c(1, 0, 0, 1, 1, 0, 1) it would be 4.
What is important I want to look for exactly the same vector. Thus, for c(1, 1) inside c(1, 0, 1, 1, 1, 0) it is FALSE as c(1, 1) != c(1, 1, 1).
For now I am checking if the short vector is contained in the long like this:
any(with(rle(longVec), lengths[as.logical(values)]) == length(shortVec)
But I don't know how to determine the index of it...
This function should work:
my_function <- function(x, find) {
# we create two matrix from rle function
m = matrix(unlist(rle(x)), nrow=2, byrow = T)
n = matrix(unlist(rle(find)), nrow=2, byrow = T)
# for each column in m we see if its equal to n
temp_bool = apply(m, 2, function(x) x == n) # this gives a matrix of T/F
# then we simply sum by columns, if we have at least a 2 it means that we found (1,1) at least once
temp_bool = apply(temp_bool, 2, sum)
# updated part
if (any(temp_bool==2)) {
return(position = which(temp_bool==2)+1)
} else {
return(position = FALSE)
}
}
my_function(x, find)
#[1] 4
my_function(y, find)
#[1] FALSE
To make it more clear here I show the results from those two apply:
apply(m, 2, function(x) x == n)
# [,1] [,2] [,3] [,4] [,5]
# [1,] FALSE TRUE TRUE FALSE FALSE
# [2,] TRUE FALSE TRUE FALSE TRUE # TRUE-TRUE on column 3 is what we seek
apply(temp_bool, 2, sum)
#[1] 1 1 2 0 1
Example data:
x <- c(1,0,0,1,1,0,1)
y <- c(1,0,1,1,1,0)
find <- c(1,1) # as pointed this needs to be a pair of the same number
Assuming that shortVec contains only ones and longVec contains only zeros and ones use rle and rep to create a vector lens the same length as longVec such that each element in each run is replaced by that run's length. Then multiply that by longVec to zero out the elements corresponding to 0 in longVec. Now return the indices corresponding to elements equal to length(shortVec) and take the first.
lookup <- function(shortVec, longVec) {
lens <- with(rle(longVec), rep(lengths, lengths))
which(lens * longVec == length(shortVec))[1]
}
lookup(c(1,1), c(1, 0, 0, 1, 1, 0, 1))
## [1] 4
lookup(c(1,1), c(1, 0, 0, 1, 1, 1, 0, 1))
## [1] NA
This works for the examples below.
a <- c(1,1)
b <- c(1,0,1,1,0,0)
c <- c(1,0,1,1,1,0)
f <- function(x, y) {
len.x <- length(x)
len.y <- length(y)
for(i in 1:(len.y - (len.x - 1))) {
if(identical(y[i:(i + (len.x - 1))], x)){
if(y[i + len.x] != x[len.x] & y[i - 1] != x[1]) {return(TRUE)}
}
}
return(FALSE)
}
f(a, b)
# TRUE
f(a, c)
# FALSE

Apply - creating a matrix by combining two other matrices, using value from a vector to select the one to combine column from

I have a task that I am doing with an ordinary for loop. I think it can be done by one of apply functions but can't find a way to do it. Can you please if it is possible to apply apply to the problem or if there is more efficient way of solving it ?
I am aware that I can make udf and do.call() but I think it would be the same as for loop.
The problem:
I have two matrices a and b, both (m x n) and a vector of length n. I want to create third matrix (m x n) which would recieve columns from a or b based on the values of a vector.
For example:
a=
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
b=
[1, 1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]
x=
[-1, -1, 1, 1]
if x[k] is -1, c recieves column from a, if x[k] is 1 then c recieves column from b, which yields:
c=
[0, 0, 1, 0]
[0, 0, 1, 0]
[0, 0, 1, 0]
[0, 0, 1, 0]
Reproducible example:
a <- matrix(rep(0, 16), nrow = 4, ncol = 4)
b <- matrix(rep(1, 16), nrow = 4, ncol = 4)
x <- c(-1,-1, 1,-1)
c <- matrix(NA, nrow = 4, ncol = 4)
for (i in 1:length(x)){
if (x[[i]] < 0){
c[,i] <- a[,i]
} else {
c[,i] <- b[,i]
}
}
Is there any more efficient solution ?
Regards,
P.
We can either use ifelse after making the 'x' as the same length as 'a/b' by replicating each of the 'x' elements. The col is a convenient function to do that.
c <- a
c[] <- ifelse(x[col(a)]==-1, a, b)
Or as in the previous step, we create a logical vector (x==1), coerce to binary with +, make the length the same as 'a', specify the ncol in the matrix.
matrix(+(x==1)[col(a)], ncol=ncol(a))
# [,1] [,2] [,3] [,4]
#[1,] 0 0 1 0
#[2,] 0 0 1 0
#[3,] 0 0 1 0
#[4,] 0 0 1 0

Determining Whether a Matrix Has At Least One Zero Element

I'm sure this is trivial - nonetheless, any help would be appreciated.
The problem is simple: given a matrix, I'd like to get TRUE if the matrix in question has at least one element equal to zero. So, checking
A <- matrix(c(1, 2, 3, 4, 5, 0), nrow = 2, ncol = 3, byrow = TRUE)
> A
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 0
would return TRUE, while
B <- matrix(c(1, 2, 3, 4, 5, 6), nrow = 2, ncol = 3, byrow = TRUE)
> B
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6
would return FALSE.
Something like
if ( A == 0 ) { cat("\nZero detected")}
gives a warning. Is there a simple way to do this?
The warning is generated because you're presenting a vector of logical to if, which expects a single value. any is a function to tell if any of the logical values are TRUE:
any(A==0)
## [1] TRUE
any(B==0)
## [1] FALSE
There's also a function all which determines if all of the values in a logical vector are TRUE.
Try
0 %in% A
It should return TRUE or FALSE. It works for NA too:
x = matrix(1:24, ncol = 4)
x[3, 3] = NA
NA %in% x
#TRUE

Get rows which do not contain 0

I would like to make a new matrix from another matrix but only with rows which do not contain 0, how can I do that?
Here is a more vectorized way.
x <- matrix(c(0,0,0,1,1,0,1,1,1,1), ncol = 2, byrow = TRUE)
x[rowSums(x==0)==0,]
I found that it could by done very simply
x <- matrix(c(0,0,0,1,1,0,1,1,1,1), ncol = 2, byrow = TRUE)
y <- cbind (x[which(x[,1]*x[,2] >0), 1:2])
I am only piecing together the great suggestions others have already given. I like the ability to store this as a function and generalize to values besides 1 including categorcal values (also selects positively or negatively using the select argument):
v.omit <- function(dataframe, v = 0, select = "neg") {
switch(select,
neg = dataframe[apply(dataframe, 1, function(y) !any(y %in% (v))), ],
pos = dataframe[apply(dataframe, 1, function(y) any(y %in% (v))), ])
}
Let's try it.
x <- matrix(c(0,0,0,1,1,0,1,1,1,1,NA,1), ncol = 2, byrow = TRUE)
v.omit(x)
v.omit(mtcars, 0)
v.omit(mtcars, 1)
v.omit(CO2, "chilled")
v.omit(mtcars, c(4,3))
v.omit(CO2, c('Quebec', 'chilled'))
v.omit(x, select="pos")
v.omit(CO2, c('Quebec', 'chilled'), select="pos")
v.omit(x, NA)
v.omit(x, c(0, NA))
Please do not mark my answer as the correct one as others have answered before me, this is just to extend the conversation. Thanks for the code and the question.
I'm sure there are better ways, but here's one approach. We'll use apply() and the all() function to create a boolean vector to index into the matrix of interest.
x <- matrix(c(0,0,0,1,1,0,1,1,1,1), ncol = 2, byrow = TRUE)
x
> x
[,1] [,2]
[1,] 0 0
[2,] 0 1
[3,] 1 0
[4,] 1 1
[5,] 1 1
> x[apply(x, 1, function(y) all(y > 0)) ,]
[,1] [,2]
[1,] 1 1
[2,] 1 1

Resources