I am new to R. I have two matrices:
Amat<-matrix(data=c(11:20,NA,NA,NA,NA,25:30),nrow = 4,ncol = 5)
Bmat<-matrix(data=c(1:6,NA,NA,NA,NA,11:20),nrow = 4,ncol = 5)
I want to build a third matrix Cmat of dimension 4x5 (same as Amat & Bmat) in such a way that data from Amat and Bmat are comapred as below:
if(is.na(Amat)!="TRUE" && is.na(Bmat)!="TRUE") {1} else {0}
i.e. Cmat should be filled with '1' for the respective position if both matrices (Amat & Bmat) doesn't have NA.
Can anyone help me to approach for this without going for loop? Thanks in advance!
We can do this by coercing the logical matrix (!is.na(Amat) & !is.na(Bmat)) to binary (+)
Cmat <- +(!is.na(Amat) & !is.na(Bmat))
Cmat
# [,1] [,2] [,3] [,4] [,5]
#[1,] 1 1 0 0 1
#[2,] 1 1 0 0 1
#[3,] 1 0 0 1 1
#[4,] 1 0 0 1 1
Or other variations include
+(!is.na(Amat*Bmat))
Or
+(!is.na(Amat + Bmat))
Related
I have seen similar questions to this in my research on this site, but not this exact question (most answers involve creating a sparse matrix from a list).
I have a list of adjacent polygons, but wish to convert it to a full matrix. I can do this rather clunkily with nested for loops, but I am trying to improve my coding by relying less on these. So in essence, what I would like is to get from this:
my_list <- list("1" = c(2, 3),
"2" = 1,
"3" = 1)
to something that looks like this:
# [,1] [,2] [,3]
#[1,] 0 1 1
#[2,] 1 0 0
#[3,] 1 0 0
without resorting to this:
for(i in 1:3{
for(j in 1:3{
[look to list to see if there is a value corresponding to (i, j),
if so insert 1, if not, zero]
}
}
Thank you very much for your time.
You can try sapply and tabulate
nbins <- max(unlist(my_list)) # 3
sapply(my_list, function(x) tabulate(x, nbins = nbins))
# [,1] [,2] [,3]
#[1,] 0 1 1
#[2,] 1 0 0
#[3,] 1 0 0
Could be written without the anonymous function, and with a safety check as
vapply(my_list, tabulate, nbins = nbins, FUN.VALUE = integer(nbins))
You can use sapply :
n <- 1:max(unlist(my_list))
sapply(my_list, function(x) +(n %in% x))
# [,1] [,2] [,3]
#[1,] 0 1 1
#[2,] 1 0 0
#[3,] 1 0 0
I converted an image into a 100x100 matrix of 0's and 1's.
An ntile is nXn selection. I am trying to calculate how many 2 tiles there are in the matrix with the 2 left most entries are 1 and the two most right entries are 0.
Eg
[1 0]
[1 0]
Any idea on how to start this?. I am quite new to R. Thanks very much in advance.
You can subset all chunks of larger matrix with dimensions equal to that of ntile and then check if all the elements of the chunk match the corresponding elements of ntile.
#Data
set.seed(1)
m = matrix(sample(1:0, 16, TRUE), 4)
m[3, 4] = 0
ntile = rbind(1:0, 1:0)
n = dim(ntile)
ans = t(sapply(n[1]:nrow(m), function(i){
sapply(n[2]:ncol(m), function(j){
temp = m[(i- nrow(ntile) + 1):i, (j - ncol(ntile) + 1):j]
all(temp == ntile)
})
}))
ans
# [,1] [,2] [,3]
#[1,] FALSE FALSE FALSE
#[2,] FALSE FALSE FALSE
#[3,] FALSE FALSE TRUE
sum(ans)
#[1] 1
Here is a simple solution if I understood your question correctly:
set.seed(123)
size <- 4
m <- matrix(sample(0:1, 12, replace = TRUE), size-1, size)
m <- rbind(m, c(0,0,1,0))
sum(m[1:(size-1),1:(size-1)] == 1 & m[2:size,1:(size-1)] == 1 &
m[1:(size-1),2:size] == 0 & m[2:size,2:size] == 0)
Input
[,1] [,2] [,3] [,4]
[1,] 0 1 1 0
[2,] 1 1 1 1
[3,] 0 0 1 0
[4,] 0 0 1 0
Output
# 1
You can make sure that the number of 2 tiles is 1.
Suppose I have a symmetric matrix:
> mat <- matrix(c(1,0,1,0,0,0,1,0,1,1,0,0,0,0,0,0), ncol=4, nrow=4)
> mat
[,1] [,2] [,3] [,4]
[1,] 1 0 1 0
[2,] 0 0 1 0
[3,] 1 1 0 0
[4,] 0 0 0 0
which I would like to analyse:
> which(mat==1, arr.ind=T)
row col
[1,] 1 1
[2,] 3 1
[3,] 3 2
[4,] 1 3
[5,] 2 3
now the question is: how am I not considering duplicated cells? As the resulting index matrix shows, I have the rows 2 and 4 pointing respectively to (3,1) and (1,3), which is the same cell.
How do I avoid such a situation? I only need a reference for each cell, even though the matrix is symmetric. Is there an easy way to deal with such situations?
EDIT:
I was thinking about using upper.tri or lower.tri but in this case what I get is an vector version of the matrix and I am not able to get back to the (row, col) notation.
> which(mat[upper.tri(mat)]==1, arr.ind=T)
[1] 2 3
EDIT II
expected output would be something like an unique over the couple of (row, col) and (col, row):
row col
[1,] 1 1
[2,] 3 1
[3,] 3 2
Since you have symmetrical matrix you could do
which(mat == 1 & upper.tri(mat, diag = TRUE), arr.ind = TRUE)
# row col
#[1,] 1 1
#[2,] 1 3
#[3,] 2 3
OR
which(mat == 1 & lower.tri(mat, diag = TRUE), arr.ind = TRUE)
Suppose I have a list of matrices. Suppose further I have found the smallest values by the column.
Here is my last question
I really need to know from which matrix each smallest value is selected. My original function is very complicated. Therefore, I provided a simple example. I have one idea and really do not know to implement it correctly in R.
My idea is:
Suppose that [i,j] is the elements of the matrix. Then,
if(d[[1]][i,j] < d[[2]][i,j]){
d[[1]][i,j] <– "x"
}else { d[[2]][i,j] <– "z"}
So, I would like to sign the name of the matrix that corresponds to each smallest value. Then, store the names in a separate matrix. So, then I can see the values in one matrix and their corresponding names (from where they come from) in another matrix
For example,
y <- c(3,2,4,5,6, 4,5,5,6,7)
x[lower.tri(x,diag=F)] <- y
> x
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 0 0
[2,] 3 0 0 0 0
[3,] 2 6 0 0 0
[4,] 4 4 5 0 0
[5,] 5 5 6 7 0
k <- c(1,4,5,2,5,-4,4,4,4,5)
z[lower.tri(z,diag=F)] <- k
> z
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 0 0
[2,] 1 0 0 0 0
[3,] 4 5 0 0 0
[4,] 5 -4 4 0 0
[5,] 2 4 4 5 0
d <- list(z, x)
Then:
do.call(pmin, d) (answered by #akrun)
Then, I will only get the matrix with smallest values. I would like to know where each value is come from?
Any idea or help, please?
You can use Map and do.call to create your own functions that will be applied element-wise to a list of inputs,
in your case a list of matrices.
pwhich.min <- function(...) {
which.min(c(...)) # which.min takes a single vector as input
}
di <- unlist(do.call(Map, c(list(f = pwhich.min), d)))
dim(di) <- dim(x) # take dimension from one of the inputs
di
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 2 1 1 1 1
[3,] 1 2 1 1 1
[4,] 1 2 2 1 1
[5,] 2 2 2 2 1
EDIT:
To elaborate,
you could do something like Map(f = min, z, x) to apply min to each pair of values in z and x,
although in that case min already supports arbitrary amount of inputs through an ellipsis (...).
By contrast,
which.min only takes a single vector as input,
so you need a wrapper with an ellipsis that combines all values into a vector
(pwhich.min above).
Since you may want to have more than two matrices,
you can put them all in a list,
and use do.call to put each element in the list as a parameter to the function you specify in f.
Or another option would be to convert it to a 3D array and use apply with which.min
apply(array(unlist(d), c(5, 5, 2)), c(1, 2), which.min)
Or with pmap from purrr
library(purrr)
pmap_int(d, ~ which.min(c(...))) %>%
array(., dim(x))
I have a matrix like this:
[,1] [,2] [,3]
[1,] 0 1 0
[2,] 1 1 0
[3,] 0 0 1
The ones in each row represent the maximum values per row for e.g. i had the matrix
[,1] [,2] [,3]
[1,] 11 32 12
[2,] 16 16 14
[3,] 19 18 27
Now in this matrix in the second row I had two same maximum values (16) which got replaced by two 1's in the second row in the previous matrix, now I want to remove duplicate maximum values in my rows of a matrix so in essence what I need is something like this:
[,1] [,2] [,3]
[1,] 0 1 0
[2,] 1 0 0
[3,] 0 0 1
i.e keep one maximum value per row at random (ties should be broken at random and only one maximum value kept) and make all the entries other than that zero. Please can any one provide me a code snippet to solve this problem.
Or you could use. This would be faster.
ret[cbind(seq_len(nrow(mat2)),max.col(mat2, "first"))] <- 1
ret
# [,1] [,2] [,3]
#[1,] 0 1 0
#[2,] 1 0 0
#[3,] 0 0 1
data
mat1 <- matrix(c(0,1,0, 1,1,0,0,0,1), ncol=3)
mat2 <- matrix(c(11,16,19, 32, 16, 18, 12, 14, 27), ncol=3)
ret <- matrix(0, ncol(mat1), nrow(mat1))
if mat is your original matrix,
Create an empty matrix full of zeros, of the correct size and dim
ret <- matrix(rep(0, length(mat)), ncol=ncol(mat))
assign the required values to 1. Note that which.max breaks tie by choosing the first occurrence.
ret[ cbind(seq(nrow(mat)), apply(mat, 1, which.max)) ] <- 1
ret
[,1] [,2] [,3]
[1,] 0 1 0
[2,] 1 0 0
[3,] 0 0 1
Alternatively, if you truly want to split ties at random, you would use something like this as the index to ret:
cbind(seq(nrow(mat)), apply(mat, 1, function(x)
sample(which(x == max(x)), 1)
))