Matrix to vector minimum comparison without using apply in R - r

I am trying to create a function that takes in a matrix M and a vector v. It should then take the elementwise minimum between columns of M and v. As such, the number of rows of M = length(v)
For example, the below does it for two vectors of equal length. I want it to work for a matrix compared to a vector.
vectorelementwisemin = function(x,y){ #x is a vector, y is a vector (same length)
ind = which(x > y)
z = x
z[ind] <- y[ind]
return(z)
}
For example, the vectorized function could take in:
M
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,] 0 0 0 0 0 0 0 0 0 0 0 0
[2,] 2 2 5 4 2 3 4 1 4 4 4 2
[3,] 0 0 0 0 0 0 0 0 0 0 0 0
[4,] 0 0 0 0 0 0 0 0 0 0 0 0
[5,] 0 6 0 0 0 0 0 0 0 0 0 0
[6,] 0 0 0 0 0 0 0 0 0 0 0 0
v
0 4 2 1 3 0
And return
minmat(M,v)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,] 0 0 0 0 0 0 0 0 0 0 0 0
[2,] 2 2 4 4 2 3 4 1 4 4 4 2
[3,] 0 0 0 0 0 0 0 0 0 0 0 0
[4,] 0 0 0 0 0 0 0 0 0 0 0 0
[5,] 0 3 0 0 0 0 0 0 0 0 0 0
[6,] 0 0 0 0 0 0 0 0 0 0 0 0

you can just use minmat <- function(M, v) pmin(M, v) although you may want to add something like if (nrow(M) != length(v)) stop("")

Related

How to create a matrix from all possible combinations of 2 or more matrices?

Let's say, there are two matrices:
A <- B <- diag(3)
> A
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 1 0
[3,] 0 0 1
I want to create a new matrix AB, which consists of all the possible combinations of rows of A and B. Expected result:
> AB
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 0 0 1 0 0
[2,] 1 0 0 0 1 0
[3,] 1 0 0 0 0 1
[4,] 0 1 0 1 0 0
[5,] 0 1 0 0 1 0
[6,] 0 1 0 0 0 1
[7,] 0 0 1 1 0 0
[8,] 0 0 1 0 1 0
[9,] 0 0 1 0 0 1
How to do this efficiently? And can it be extended for more than two matrices?
You can use expand.grid() and take its output to index the matrix A and B,
x <- expand.grid(1:3,1:3)
cbind(A[x[,1],], B[x[,2],])
gives,
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 0 0 1 0 0
[2,] 0 1 0 0 1 0
[3,] 0 0 1 0 0 1
[4,] 1 0 0 1 0 0
[5,] 0 1 0 0 1 0
[6,] 0 0 1 0 0 1
[7,] 1 0 0 1 0 0
[8,] 0 1 0 0 1 0
[9,] 0 0 1 0 0 1
EDIT:
For more than two matrices, you can use a function like below,
myfun <- function(...) {
arguments <- list(...)
a <- expand.grid(lapply(arguments, function(x) 1:nrow(x)))
do.call(cbind,lapply(seq(a),function(x) { arguments[[x]][a[,x],] }))
}
out <- myfun(A,B,C)
head(out)
gives,
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 0 0 1 0 0 1 0 0 0
[2,] 0 1 0 1 0 0 1 0 0 0
[3,] 0 0 1 1 0 0 1 0 0 0
[4,] 1 0 0 0 1 0 1 0 0 0
[5,] 0 1 0 0 1 0 1 0 0 0
[6,] 0 0 1 0 1 0 1 0 0 0
Data:
A <- B <- diag(3)
C <- diag(4)

I want to transform a forward star representation to incidence matrix

I have a forward star representation and i want to convert to to incidence matrix i wrote the code but it gave me wrong answer
FS <- data.frame(
archsNo = c(1:12),
snode = c(1,1,2,2,3,3,4,4,5,5,6,8),
enode = c(2,4,4,5,2,5,6,7,7,8,7,7))
print(FS)
archsNo snode enode
1 1 1 2
2 2 1 4
3 3 2 4
4 4 2 5
5 5 3 2
6 6 3 5
7 7 4 6
8 8 4 7
9 9 5 7
10 10 5 8
11 11 6 7
12 12 8 7
This what i have tried :
n = 8 #number of nodes
m = 12 #number of archs
incidence <- matrix(0L,nrow=n, ncol=m)
for(row in 1:n)
{
for(col in 1:m)
{
incidence[row][col] = ifelse(row == snode[col],1,ifelse(row == enode[col],-1,0))
row
snode[col]
enode[col]
}
}
incidence
This is the result :
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,] 1 0 0 0 0 0 0 0 0 0 0 0
[2,] -1 0 0 0 0 0 0 0 0 0 0 0
[3,] 0 0 0 0 0 0 0 0 0 0 0 0
[4,] 0 0 0 0 0 0 0 0 0 0 0 0
[5,] 0 0 0 0 0 0 0 0 0 0 0 0
[6,] 0 0 0 0 0 0 0 0 0 0 0 0
[7,] 0 0 0 0 0 0 0 0 0 0 0 0
[8,] 0 0 0 0 0 0 0 0 0 0 0 0
for each cell if the node in the row is the starting node then it should contain 1 if end node then the cell should have -1 and else then 0 but this didn't happen
You don't index arrays in R with [row][col], you would use [row,col]. But here's an alternative way to fill the matrix easily without a loop
nodes <- max(FS$snode, FS$enode)
mm <- matrix(0, nrow=nodes, ncol=nrow(FS))
mm[cbind(FS$snode, FS$archsNo)] <- 1
mm[cbind(FS$enode, FS$archsNo)] <- -1
mm
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
# [1,] 1 1 0 0 0 0 0 0 0 0 0 0
# [2,] -1 0 1 1 -1 0 0 0 0 0 0 0
# [3,] 0 0 0 0 1 1 0 0 0 0 0 0
# [4,] 0 -1 -1 0 0 0 1 1 0 0 0 0
# [5,] 0 0 0 -1 0 -1 0 0 1 1 0 0
# [6,] 0 0 0 0 0 0 -1 0 0 0 1 0
# [7,] 0 0 0 0 0 0 0 -1 -1 0 -1 -1
# [8,] 0 0 0 0 0 0 0 0 0 -1 0 1

Set values along a diagonal in a matrix

I am trying to use the matrix() and diag() functions to create the following pattern, but with a 100 x 100 matrix rather than 5 x 5.
5 x 5 matrix:
| 0 1 0 0 0 |
| 1 0 1 0 0 |
| 0 1 0 1 0 |
| 0 0 1 0 1 |
| 0 0 0 1 0 |
In other words, I want to have two diagonals with values of 1, one to the left of the main diagonal, and one to the right of the main diagonal.
The diag() function (actually the diag<- function) can be used for assignment:
mat <- matrix( 0, 100,100)
diag(mat) <- 1
mat[1:10,1:10]
#-----------
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 0 0 0 0 0 0 0 0 0
[2,] 0 1 0 0 0 0 0 0 0 0
[3,] 0 0 1 0 0 0 0 0 0 0
[4,] 0 0 0 1 0 0 0 0 0 0
[5,] 0 0 0 0 1 0 0 0 0 0
[6,] 0 0 0 0 0 1 0 0 0 0
[7,] 0 0 0 0 0 0 1 0 0 0
[8,] 0 0 0 0 0 0 0 1 0 0
[9,] 0 0 0 0 0 0 0 0 1 0
[10,] 0 0 0 0 0 0 0 0 0 1
You, however, want the sub-diagonal and super-diagonal to be assigned values, so use logical expressions with col and row:
mat <- matrix( 0, 100,100)
mat[row(mat)==col(mat)-1] <- 1
mat[row(mat)==col(mat)+1] <- 1
mat[1:10,1:10]
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 0 1 0 0 0 0 0 0 0 0
[2,] 1 0 1 0 0 0 0 0 0 0
[3,] 0 1 0 1 0 0 0 0 0 0
[4,] 0 0 1 0 1 0 0 0 0 0
[5,] 0 0 0 1 0 1 0 0 0 0
[6,] 0 0 0 0 1 0 1 0 0 0
[7,] 0 0 0 0 0 1 0 1 0 0
[8,] 0 0 0 0 0 0 1 0 1 0
[9,] 0 0 0 0 0 0 0 1 0 1
[10,] 0 0 0 0 0 0 0 0 1 0
(This method does not depend on having a square matrix. I have a vague memory that there is a faster method that does not require using row and col. For very large objects each of those functions returns a matrix of the same dimensions as their arguments.)
For the main diagonal, the row and column indices are the same. For the other diagonals, there is a difference of 1 between the row index and column index. Generate those indices directly and assign values in those indices.
sz = 5
m = matrix(0, sz, sz)
inds1 = cbind(r = 1:(sz-1), c = 2:sz)
inds2 = cbind(r = 2:sz, c = 1:(sz-1))
m[inds1] = 1
m[inds2] = 1
m
# OR, to make it concise
m = matrix(0, sz, sz)
inds = rbind(cbind(1:(sz-1), 2:sz), cbind(2:sz, 1:(sz-1)))
replace(m, inds, 1)
# [,1] [,2] [,3] [,4] [,5]
#[1,] 0 1 0 0 0
#[2,] 1 0 1 0 0
#[3,] 0 1 0 1 0
#[4,] 0 0 1 0 1
#[5,] 0 0 0 1 0
We could create a function using a math trick which would work for all square matrix.
get_off_diagonal_1s <- function(n) {
#Create a matrix with all 0's
mat <- matrix(0, ncol = n, nrow = n)
#Subtract row indices by column indices
inds = row(mat) - col(mat)
#Replace values where inds is 1 or -1
mat[inds == 1 | inds == -1] = 1
mat
}
get_off_diagonal_1s(5)
# [,1] [,2] [,3] [,4] [,5]
#[1,] 0 1 0 0 0
#[2,] 1 0 1 0 0
#[3,] 0 1 0 1 0
#[4,] 0 0 1 0 1
#[5,] 0 0 0 1 0
get_off_diagonal_1s(8)
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
#[1,] 0 1 0 0 0 0 0 0
#[2,] 1 0 1 0 0 0 0 0
#[3,] 0 1 0 1 0 0 0 0
#[4,] 0 0 1 0 1 0 0 0
#[5,] 0 0 0 1 0 1 0 0
#[6,] 0 0 0 0 1 0 1 0
#[7,] 0 0 0 0 0 1 0 1
#[8,] 0 0 0 0 0 0 1 0

R programming: How to do replace values by row?

How to do a row-wise replacement of values using R?
I have a Matrix and I would like to replace some of its values using an index vector. The problem is that R automatically does a column-wise extraction of the values as opposed to a row-wise.
You will find my code and results below:
Matrix=matrix(rep(0,42),nrow=6,ncol=7,byrow=TRUE)
v=c(1,7,11,16,18)
Matrix[v]=1
Matrix
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 1 1 0 0 0 0 0
[2,] 0 0 0 0 0 0 0
[3,] 0 0 0 0 0 0 0
[4,] 0 0 1 0 0 0 0
[5,] 0 1 0 0 0 0 0
[6,] 0 0 1 0 0 0 0
What I actually want to get is the row-wise version of this meaning:
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 1 0 0 0 0 0 1
[2,] 0 0 0 1 0 0 0
[3,] 0 1 0 1 0 0 0
[4,] 0 0 0 0 0 0 0
[5,] 0 0 0 0 0 0 0
[6,] 0 0 0 0 0 0 0
>
Apparently R does a column-wise replacement of values by default.
What is the best way to obtain a row-wise replacement of the values?
Thanks!
You could recalculate the onedimensional indizes to row- and column-indices. Supposing you have calculated the row-indices in the first column of the matrix Ind and the columnindices in the second column of Ind you can do Matrix[Ind] <- 1
Matrix <- matrix(rep(0,42),nrow=6,ncol=7,byrow=TRUE)
v <- c(1,7,11,16,18)
Row <- (v-1) %/% ncol(Matrix) +1
Col <- (v-1) %% ncol(Matrix) +1
Matrix[cbind(Row,Col)] <- 1
Matrix
# [,1] [,2] [,3] [,4] [,5] [,6] [,7]
# [1,] 1 0 0 0 0 0 1
# [2,] 0 0 0 1 0 0 0
# [3,] 0 1 0 1 0 0 0
# [4,] 0 0 0 0 0 0 0
# [5,] 0 0 0 0 0 0 0
# [6,] 0 0 0 0 0 0 0
We can do
+(matrix(seq_along(Matrix) %in% v, ncol=ncol(Matrix), nrow=nrow(Matrix), byrow=TRUE))
# [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#[1,] 1 0 0 0 0 0 1
#[2,] 0 0 0 1 0 0 0
#[3,] 0 1 0 1 0 0 0
#[4,] 0 0 0 0 0 0 0
#[5,] 0 0 0 0 0 0 0
#[6,] 0 0 0 0 0 0 0
You could redo your 1's to make them row-wise or you can do the following:
Matrix=matrix(rep(0,42),nrow=6,ncol=7,byrow=TRUE)
v=c(1,7,11,16,18)
Matrix<-t(Matrix)
Matrix[v]=1
Matrix<-t(Matrix)
Matrix
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 1 0 0 0 0 0 1
[2,] 0 0 0 1 0 0 0
[3,] 0 1 0 1 0 0 0
[4,] 0 0 0 0 0 0 0
[5,] 0 0 0 0 0 0 0
[6,] 0 0 0 0 0 0 0

generating numerical clusters from matrix values of a minimal size

I have a matrix of 1's and 0's. What I would like to do is group the cells that have 1's into clusters and count the number of clusters that exist in the matrix as well as the size of these clusters.
If n number (in this case at least 4 cells with the value 1 near each other) of 1's are near each other (either immediately up, down, left or right from each other then consider them a single cluster and output the number of clusters and their size.
For example the matrix looks like this:
> m
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 0 0 0 0 0 0 0 0 0
[2,] 1 1 1 0 0 0 0 0 0 0
[3,] 0 0 1 0 0 0 0 0 0 0
[4,] 0 0 1 0 0 0 0 0 0 0
[5,] 0 0 1 0 0 0 0 1 1 0
[6,] 0 0 0 0 0 0 0 0 1 1
the number of clusters this matrix has is 2 clusters. One cluster of 7 1's and another cluster of 4 1's. I have been having quite a bit of trouble trying to get this to work and can't seem to figure it out.
The output can be something simple like this:
> output
cluster size
1 7
2 4
You could use the function ConnCompLabel from the package SDMTools to label the connected components in the binary matrix:
R> ConnCompLabel(m)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 0 0 0 0 0 0 0 0 0
[2,] 1 1 1 0 0 0 0 0 0 0
[3,] 0 0 1 0 0 0 0 0 0 0
[4,] 0 0 1 0 0 0 0 0 0 0
[5,] 0 0 1 0 0 0 0 2 2 0
[6,] 0 0 0 0 0 0 0 0 2 2
R> tab <- table(ConnCompLabel(m))[-1]
R> tab[tab >= 4]
1 2
7 4

Resources