Calculate nXn in matrix - R? - r

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.

Related

Changing particular cells of a Matrix iteratively in R

Suppose that we have a (4,4) matrix. My goal is to change iteratively that cells (1,1),(2,1),(3,1),(1,2),(2,2),(1,3)
I wrote the following
for(i in 1:3){
for(j in 1:3){
if(i>j){
A[i,j] = A[i,j] + sample(c(-1,1),prob=c(0.5,0.5))
}
}
However, it doesn't change the correct cells and misses cells that have to be changed.
The matrix A can be of the form
A = matrix(c(1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,0),4,4,byrow=T)
I think that the following chunk of code might be the solution, at least it gives the correct answer for a few runs that I did.
A = matrix(c(1,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0),4,4,byrow=T)
k = 0
for(i in 1:3){
for(j in 1:(3-k)){
A[i,j] = A[i,j] + sample(c(-1,1),prob=c(0.5,0.5), size = 1)
}
k = k + 1
}
I think you simple forgot to set the size= parameter of sample to get one draw of the Rademacher universe.
set.seed(42)
for (i in 1:3) {
for (j in 1:3) {
if (i > j) {
A[i, j] <- A[i, j] + sample(c(-1, 1), size=1, prob=c(0.5, 0.5))
}
}
}
A
# [,1] [,2] [,3] [,4]
# [1,] 1 1 1 1
# [2,] 0 1 1 0
# [3,] 0 2 0 0
# [4,] 1 0 0 0
Another idea is to use a permutation matrix, which you may subset to your needs, and over which you may loop.
id <- RcppAlgos::permuteGeneral(ncol(B) - 1, ncol(B) - 2, repetition=T)
(id <- id[c(1, 4, 7, 2, 5, 3), ])
# [,1] [,2]
# [1,] 1 1
# [2,] 2 1
# [3,] 3 1
# [4,] 1 2
# [5,] 2 2
# [6,] 1 3
set.seed(42)
for (i in 1:nrow(id)) {
A[id[i, 1], id[i, 2]] <- A[id[i, 1], id[i, 2]] +
sample(c(-1, 1), size=1, prob=c(0.5, 0.5))
}
A
# [,1] [,2] [,3] [,4]
# [1,] 0 0 0 1
# [2,] 0 0 1 0
# [3,] 2 1 0 0
# [4,] 1 0 0 0
We can create a row/column index (vectorized approach) by cbinding the vector of index. Use the index to subset the cells of the matrix and assign (<-) after adding the sample output to those elements
n <- 3
j1 <- rep(seq_len(n), rev(seq_len(n)))
i1 <- ave(j1, j1, FUN = seq_along)
ind <- cbind(i1, j1)
ind
# i1 j1
#[1,] 1 1
#[2,] 2 1
#[3,] 3 1
#[4,] 1 2
#[5,] 2 2
#[6,] 1 3
A[ind] <- A[ind] + sample(c(-1,1),prob=c(0.5,0.5),
size = nrow(ind), replace= TRUE)

Create matrix with for-loop

I am trying to create the following matrix A for n rows and n+1 columns. n will likely be around 20 or 30, but for the purpose of the question I put it at 4 and 5.
Here is what I have so far:
N <- 5 # n+1
n <- 4 # n
columns <- list()
# first column:
columns[1] <- c(-1, 1, rep(0, N-2))
# all other columns:
for(i in N:2) {
columns[i] <- c((rep(0, N-i), 1, -2, 1, rep(0, i-3)))
}
# combine into matrix:
A <- cbind(columns)
I keep getting the following error msg:
In columns[1] <- c(-1, 1, rep(0, N - 2)) :
number of items to replace is not a multiple of replacement length
And later
"for(i in N:2) {
columns[i] <- c((rep(0, N-i),"
}
Error: unexpected '}' in "}"
I guess you can try the for loop below to create your matrix A:
N <- 5
n <- 4
A <- matrix(0,n,N)
for (i in 1:nrow(A)) {
if (i == 1) {
A[i,1:2] <- c(-1,1)
} else {
A[i,i+(-1:1)] <- c(1,-2,1)
}
}
such that
> A
[,1] [,2] [,3] [,4] [,5]
[1,] -1 1 0 0 0
[2,] 1 -2 1 0 0
[3,] 0 1 -2 1 0
[4,] 0 0 1 -2 1
Another solution is to use outer, and this method would be faster and looks more compact than the for loop approach, i.e.,
A <- `diag<-`(replace(z<-abs(outer(1:n,1:N,"-")),!z %in% c(0,1),0),
c(-1,rep(-2,length(diag(z))-1)))
I thought this would be fast compared to the loop, but when I tested on a 5000x5001 example, the loop in ThomasIsCoding's answer was about 5x faster. Go with that one!
N = 5
n = N - 1
A = matrix(0, nrow = n, ncol = N)
delta = row(A) - col(A)
diag(A) = -2
A[delta %in% c(1, -1)] = 1
A[1, 1] = -1
A
# [,1] [,2] [,3] [,4] [,5]
# [1,] -1 1 0 0 0
# [2,] 1 -2 1 0 0
# [3,] 0 1 -2 1 0
# [4,] 0 0 1 -2 1
You could use data.table::shift to shift the vector c(1, -2, 1, 0) by all increments from -1 (backwards shift / lead by 1) to n - 1 (forward shift / lagged by n - 1) and then cbind all the shifted outputs together. The first-row first-column element doesn't follow this pattern so that's fixed at the end.
library(data.table)
out <- do.call(cbind, shift(c(1, -2, 1, 0), seq(-1, n - 1), fill = 0))
out[1, 1] <- -1
out
# [,1] [,2] [,3] [,4] [,5]
# [1,] -1 1 0 0 0
# [2,] 1 -2 1 0 0
# [3,] 0 1 -2 1 0
# [4,] 0 0 1 -2 1

R: Populating a matrix using data from two other matrices using condition

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))

Write a value for maximum/minimum between two values

I have a two-column matrix and I want to produce a new matrix/data.frame where Col N has 1 if is maximum, 0 otherwise (they are never equal). This is my attempt:
testM <- matrix(c(1,2,3, 1,1,5), ncol = 2, byrow = T)
>testM
V1 V2
1 1 2
2 3 1
3 1 5
apply(data.frame(testM), 1, function(row) ifelse(max(row[1],row[2]),1,0))
I expect to have:
0 1
1 0
0 1
because of the 0,1 parameters in max() function, but I just get
[1] 1 1 1
Any ideas?
Or using pmax
testM <- matrix(c(1,2,3, 1,1,5), ncol = 2, byrow = T)
--(testM==pmax(testM[,1],testM[,2]))
V1 V2
[1,] 0 1
[2,] 1 0
[3,] 0 1
You can perform arithmetic on Booleans in R! Just check if an element in each row is equal to it's max value and multiply by 1.
t(apply(testM, 1, function(row) 1*(row == max(row))))
You can use max.col and col to produce a logical matrix:
res <- col(testM) == max.col(testM)
res
[,1] [,2]
[1,] FALSE TRUE
[2,] TRUE FALSE
[3,] FALSE TRUE
If you want it as 0/1, you can do:
res <- as.integer(col(testM) == max.col(testM)) # this removes the dimension
dim(res) <- dim(testM) # puts the dimension back
res
[,1] [,2]
[1,] 0 1
[2,] 1 0
[3,] 0 1

Combinations of vectors (1 x n) taken m at a time from a matrix (k x n)

I'm new on this forum. I work in R.
I have a matrix (k x n) and I have to considere all combinations of the rows vectors (1 x n) taken 2, 3, 4 at a time.
Example:
Consider a matrix m = diag(c(rep(1, 3))),
I want the combinations of the three rows vectors (1 x n) taken 2 at a time:
first: (1,0,0) and (0,1,0)
second: (1,0,0) and (0,0,1)
third: (0,1,0) and (0,0,1)
In a second moment, for each couple, I need to compute the sum on the columns.
Any suggestion?
Thanks!
m <- diag(c(rep(1, 3)))
tmp <- combn(nrow(m), 2)
array(t(m[tmp,]), c(ncol(m), 2, ncol(tmp)))
#, , 1
#
# [,1] [,2]
#[1,] 1 0
#[2,] 0 1
#[3,] 0 0
#
#, , 2
#
# [,1] [,2]
#[1,] 1 0
#[2,] 0 0
#[3,] 0 1
#
#, , 3
#
# [,1] [,2]
#[1,] 0 0
#[2,] 1 0
#[3,] 0 1

Resources