Expand a matrix with filler values - r

Suppose I have a matrix like
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
I would like to expand it, to, say, 5x5, and fill the new cells with some given value (say 0), so that the new matrix looks like:
[,1] [,2] [,3] [,4] [,5]
[1,] 1 4 7 0 0
[2,] 2 5 8 0 0
[3,] 3 6 9 0 0
[4,] 0 0 0 0 0
[5,] 0 0 0 0 0
How could I do this with basic R functions?

We can create a matrix of 0s and assign
m2 <- matrix(0, 5, 5)
m2[seq_len(nrow(m1)), seq_len(ncol(m1))] <- m1
Or another option is bdiag
library(Matrix)
as.matrix(bdiag(m1, diag(2) * 0))
# [,1] [,2] [,3] [,4] [,5]
#[1,] 1 4 7 0 0
#[2,] 2 5 8 0 0
#[3,] 3 6 9 0 0
#[4,] 0 0 0 0 0
#[5,] 0 0 0 0 0
data
m1 <- matrix(1:9, 3, 3)

Related

How to set all rows of a list of matrices to zero using if condition statement in R

Suppose I have a matrix, mat. Suppose further that the sum of one row of this matrix is equal to zero. Then, I need to set all the coming rows (the rows after the zero row) to zero. For example,
mat <- c(1,2,0,0,0,
3,4,0,2,1,
0,0,0,1,0,
1,2,0,0,0,
0,1,0,1,0)
mat <- matrix(mat,5,5)
mat
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 0 1 0
[2,] 2 4 0 2 1
[3,] 0 0 0 0 0
[4,] 0 2 1 0 1
[5,] 0 1 0 0 0
All the entries of row 3 are zero. Hence, I want rows 4, and 5 to become zeros as well. I have a list of matrices and would like to apply the same to all the matrices using the lapply function. For simplicity, I make a list of 3 matrices similar to the mat.
mat <- c(1,2,0,0,0,
3,3,0,2,1,
0,0,0,4,0,
1,3,0,0,0,
0,1,0,1,0)
mat <- matrix(mat,5,5)
mat1 <- c(1,2,0,0,0,
3,4,0,2,1,
0,0,0,1,0,
1,2,0,0,0,
0,1,0,1,0)
mat1 <- matrix(mat1,5,5)
mat2 <- c(1,2,0,0,0,
3,4,0,2,1,
0,0,0,2,0,
1,2,0,0,0,
0,2,0,3,0)
mat2 <- matrix(mat2,5,5)
Mat <- list(mat1, mat2, mat3)
You did not actually post mat3 in your data so I just used mat3 <- matrix(1, 5, 5), i.e. a 5x5 matrix of ones. This was to ensure it could handle cases where there is no row where all values are zero.
This will return a list of matrices where all rows are zero after the first row of zeroes:
lapply(Mat, \(mat) {
first_zero_row <- which(rowSums(mat)==0)[1]
if(!is.na(first_zero_row)) {
mat[first_zero_row:nrow(mat),] <- 0
}
mat
})
Output:
[[1]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 0 1 0
[2,] 2 4 0 2 1
[3,] 0 0 0 0 0
[4,] 0 0 0 0 0
[5,] 0 0 0 0 0
[[2]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 0 1 0
[2,] 2 4 0 2 2
[3,] 0 0 0 0 0
[4,] 0 0 0 0 0
[5,] 0 0 0 0 0
[[3]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 1 1 1 1 1
[3,] 1 1 1 1 1
[4,] 1 1 1 1 1
[5,] 1 1 1 1 1
Another option could be:
lapply(Mat, function(x) {x[cumsum(rowSums(x != 0) == 0) != 0, ] <- 0; x})
[[1]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 0 1 0
[2,] 2 3 0 3 1
[3,] 0 0 0 0 0
[4,] 0 0 0 0 0
[5,] 0 0 0 0 0
[[2]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 0 1 0
[2,] 2 4 0 2 1
[3,] 0 0 0 0 0
[4,] 0 0 0 0 0
[5,] 0 0 0 0 0
[[3]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 0 1 0
[2,] 2 4 0 2 2
[3,] 0 0 0 1 0
[4,] 0 2 2 0 3
[5,] 0 1 0 0 0

Working with matrix in R. Place an element in matrix

I have a distance matrix. For example :
d<-matrix(c(0,2,3,7,11,0,13,6,8,5,0,12,6,53,12,0), nrow = 4, ncol = 4)
d
[,1] [,2] [,3] [,4]
[1,] 0 11 8 6
[2,] 2 0 5 53
[3,] 3 13 0 12
[4,] 7 6 12 0
I want to create a neighbor matrix where distance is less than or equal to 5. In matrix nb, 1 indicates not a neighbor. However, they have no neighbor (excluding itself, for example, row 1 and row 4. I would like the one with the smallest distance to be their neighbor.
> nb=(d>=5)
> nb*1
[,1] [,2] [,3] [,4]
[1,] 0 1 1 1
[2,] 0 0 1 1
[3,] 0 1 0 1
[4,] 1 1 1 0
Expected result
[,1] [,2] [,3] [,4]
[1,] 0 1 1 0
[2,] 0 0 1 1
[3,] 0 1 0 1
[4,] 1 0 1 0
I have tried and I don't know how to get it efficiently without using loop. This is just an example, my actual data has over 9000 rows. Any suggestion would be helpful. Thank you so much!
I believe the following function does what you want.
fun <- function(Dist, n = 5){
nb <- (Dist > n)*1L
for(i in seq_len(nrow(nb))) {
tmp <- Dist[i, ]
tmp[tmp == 0] <- Inf
nb[i, which.min(tmp)] <- 0L
}
nb
}
fun(d)
# [,1] [,2] [,3] [,4]
#[1,] 0 1 1 0
#[2,] 0 0 0 1
#[3,] 0 1 0 1
#[4,] 1 0 1 0
fun(d, 10)
# [,1] [,2] [,3] [,4]
#[1,] 0 1 0 0
#[2,] 0 0 0 1
#[3,] 0 1 0 1
#[4,] 0 0 1 0

How to find the smallest values of list of matrices by column

Suppose I have a list of matrices. Suppose further that I would like to find the smallest value across each value of the matrices. 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(k, x)
The expected output:
dd <– matrix(0,5,5)
dd
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 0 0
[2,] 1 0 0 0 0
[3,] 2 5 0 0 0
[4,] 4 -4 4 0 0
[5,] 2 4 4 5 0
We could use pmin to get the corresponding min value for each element across the list
do.call(pmin, d)
# [,1] [,2] [,3] [,4] [,5]
#[1,] 0 0 0 0 0
#[2,] 1 0 0 0 0
#[3,] 2 5 0 0 0
#[4,] 4 -4 4 0 0
#[5,] 2 4 4 5 0
data
d <- list(z, x)

R expand matrix dimensions using apply

I am looking to expand my 2D matrix to a 3D by applying a function to each row of matrix and returning a matrix, so that i can have a 3D matrix.
The simplest example i can think of to reproduce is, say I have a 3x3 Matrix A, i want to convert each row of A into a diagonal matrix so that now i have a 3D matrix.
testmat <- matrix(c(1,2,3,4,5,6,7,8,9), nrow = 3, byrow = TRUE) #create matrix
tesmatapply <- apply(testmat, 1, function(r) matrix(c(r[1], 0, 0, 0, r[2], 0, 0, 0, r[3]), nrow = 3, byrow= TRUE))
What i want is for testmatapply to be a 3x3x3 matrix so that tesmatapply[,,1] gives me a 3x3 diagonal matrix diag(1,2,3) corresponding to first row
But apply returns a flattened vector. leading to a 9x3 matrix How can i avoid this?
EDIT:
Basically, my expected output is an array such that:
testapply[,,1]
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 2 0
[3,] 0 0 3
testapply[,,2]
[,1] [,2] [,3]
[1,] 4 0 0
[2,] 0 5 0
[3,] 0 0 6
testapply[,,3]
[,1] [,2] [,3]
[1,] 7 0 0
[2,] 0 8 0
[3,] 0 0 9
However i am getting a 9x3 matrix:
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 0 0 0
[3,] 0 0 0
[4,] 0 0 0
[5,] 2 5 8
[6,] 0 0 0
[7,] 0 0 0
[8,] 0 0 0
[9,] 3 6 9
You can simply use the array function specifying the number of dimensions (3x3x3):
## The data
testmat <- matrix(c(1,2,3,4,5,6,7,8,9), nrow = 3, byrow = TRUE) #create matrix
## The array
array(apply(testmat, 1, diag), dim = c(3,3,3))
#, , 1
#
# [,1] [,2] [,3]
#[1,] 1 0 0
#[2,] 0 2 0
#[3,] 0 0 3
#
#, , 2
#
# [,1] [,2] [,3]
#[1,] 4 0 0
#[2,] 0 5 0
#[3,] 0 0 6
#
#, , 3
#
# [,1] [,2] [,3]
#[1,] 7 0 0
#[2,] 0 8 0
#[3,] 0 0 9
[edit]
I've replace the original apply function by diag as righlty suggested by #Tom. Of course, you can replace diag by any more complex function.
We can create a list of matrixes
lapply(split(testmat, row(testmat)), `*`, diag(3))
#$`1`
# [,1] [,2] [,3]
#[1,] 1 0 0
#[2,] 0 2 0
#[3,] 0 0 3
#$`2`
# [,1] [,2] [,3]
#[1,] 4 0 0
#[2,] 0 5 0
#[3,] 0 0 6
#$`3`
# [,1] [,2] [,3]
#[1,] 7 0 0
#[2,] 0 8 0
#[3,] 0 0 9
If we need an array as output, another option is
a1 <- replicate(3, diag(3))
replace(a1, a1==1, t(testmat))
#, , 1
# [,1] [,2] [,3]
#[1,] 1 0 0
#[2,] 0 2 0
#[3,] 0 0 3
#, , 2
# [,1] [,2] [,3]
#[1,] 4 0 0
#[2,] 0 5 0
#[3,] 0 0 6
#, , 3
# [,1] [,2] [,3]
#[1,] 7 0 0
#[2,] 0 8 0
#[3,] 0 0 9

Summing rows of rolling columns

I need to apply a rolling function that sums the rows of every two columns, so the rows of columns 1&2 will be summed, 3&4, etc.
m<-matrix(c(1,2,3,4,5,3,4,5,6,2,4,6,6,7,3,2,4,4,5,7),nrow=2,byrow=T)
I have looked at many functions including apply, rollapply, aggregate, etc. but cant seem to find one that roll sums the rows of specified columns.
I am more than capable of writing the code out the long way however am looking for an efficient solution which most likely involves a function.
sum1<-(m[,1]+m[,2])
sum2<-(m[,3]+m[,4])
sum3<-(m[,5]+m[,6])
sum4<-(m[,7]+m[,8])
sum5<-(m[,9]+m[,10])
cbind(sum1,sum2,sum3,sum4,sum5)
Thanks!
You can use this approach:
m[,seq(1, ncol(m),2)] + m[,seq(2, ncol(m), 2)]
# [,1] [,2] [,3] [,4] [,5]
#[1,] 3 7 8 9 8
#[2,] 10 13 5 8 12
You can use a matrix multiply:
> n <- ncol(m)/2
> S <- diag(n)[rep(1:n, each=2),]
> S
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 1 0 0 0 0
[3,] 0 1 0 0 0
[4,] 0 1 0 0 0
[5,] 0 0 1 0 0
[6,] 0 0 1 0 0
[7,] 0 0 0 1 0
[8,] 0 0 0 1 0
[9,] 0 0 0 0 1
[10,] 0 0 0 0 1
> m %*% S
[,1] [,2] [,3] [,4] [,5]
[1,] 3 7 8 9 8
[2,] 10 13 5 8 12
Another approach would be to convert m to a 3 dimensional array, then sum over the columns:
> X <- m
> dim(X) <- c(2,2,5)
> colSums(aperm(X, c(2,1,3)))
[,1] [,2] [,3] [,4] [,5]
[1,] 3 7 8 9 8
[2,] 10 13 5 8 12

Resources