I have two Matrices, one is binary (Zero or One) and the other is an integer matrix of the same dimensions, these are square matrices.
I'd like an efficient way of combining them in a specific way, without iteration along each element.
The way I'd like to combine them is to have a resultant matrix from matrix A and matrix B, that for the element, takes the lowest number that is not zero.
Can anyone think of a trick in R to achieve this, I've tried to do it mathematically but keep coming up short, I was wondering if there was a way to overlay the matrices with a conditional statement?
matA <- matrix(-8:7, 4,4); set.seed(123)
matB <- matrix(sample(0:1, 16, repl=TRUE), 4, 4)
matC <- matrix(NA, nrow(matA), ncol(matA))
matC[] <- pmin( matA, MatB)
matC[ matB==0] <- matA[matB==0]
matB
#-----------
[,1] [,2] [,3] [,4]
[1,] 0 1 1 1
[2,] 1 0 0 1
[3,] 0 1 1 0
[4,] 1 1 0 1
matC
#---------
[,1] [,2] [,3] [,4]
[1,] -8 -4 0 1
[2,] -7 -3 1 1
[3,] -6 -2 1 6
[4,] -5 -1 3 1
flodel's method produces:
> ifelse(matB == 0, matB, pmin(matA, matB))
[,1] [,2] [,3] [,4]
[1,] 0 -4 0 1
[2,] -7 0 0 1
[3,] 0 -2 1 0
[4,] -5 -1 0 1
mnel's method produces:
> (matB * !matA) + matA
[,1] [,2] [,3] [,4]
[1,] -8 -4 1 4
[2,] -7 -3 1 5
[3,] -6 -2 2 6
[4,] -5 -1 3 7
My guess is:
ifelse(A == 0, B, pmin(A, B))
or maybe
ifelse(A == 0, B, ifelse(B == 0, A, pmin(A, B)))
If this is not what you are looking for, please clarify (and maybe provide an example.)
From #A_Skeleton's comment on scaling, you could break your matrix into chunks:
mnel <- function(matA, matB) {
(matB * !matA) + matA
}
# method takes a function as the argument
mcombine <- function(matA, matB, method) {
chunkSize <- 10000
matC <- matrix(0, nrow(matA), ncol(matA))
for (i in 1:floor(nrow(matA) / chunkSize)) {
curRange <- (chunkSize * (i-1) + 1):(i * chunkSize)
matC[curRange,] <- method(matA[curRange,], matB[curRange,])
}
# handle case where dimensions don't divide exactly into chunks
lastRange <- i*chunkSize:nrow(matA)
matC[lastRange,] <- method(matA[lastRange,], matB[lastRange,])
matC
}
# Using mnel's method:
matC <- mcombine(matA, matB, mnel)
Related
I have a matrix and I would like to perform a calculation on each number in the matrix so that I get another matrix with the same dimensions only with the results of the calculation. This should be easy except that part of the equation is dependent on which column I am accessing because I will need to have an internal reference to the number at row [3,] within that column.
The equation I would like to apply is:
output matrix value = input_matrix value at a given position + (1- (matrix value at [3,] and in the same column as the input matrix value))
For example, For (1,1) in the matrix the calculation would be 1+(1-3)
For position (1,2) in the matrix, the calculation would be 5+(1-7)
input_matrix<- matrix(1:12, nrow = 4, ncol = 3)
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
The output matrix should end up looking like this:
[,1] [,2] [,3]
[1,] -1 -1 -1
[2,] 0 0 0
[3,] 1 1 1
[4,] 2 2 2
I have tried doing something like this:
output_matrix<-apply(input_matrix,c(1,2), function(x) x+(1-(input_matrix[3,])))
but that gives me three matrices with the wrong dimensions as the output.
I am thinking that perhaps I can perhaps just modify the function in the above calculation to get this to work, or alternatively write something that iterates over each column of the matrix but I am not sure exactly how to do this in a way that gives me the output matrix that I want.
Any help would be greatly appreciated.
I think this should work for you:
apply(input_matrix, margin = 2, function(x) x + (1 - x[3]))
[,1] [,2] [,3]
[1,] -1 -1 -1
[2,] 0 0 0
[3,] 1 1 1
[4,] 2 2 2
We could also do this in a vectorized way
input_matrix + (1 - input_matrix[3,][col(input_matrix)])
# [,1] [,2] [,3]
#[1,] -1 -1 -1
#[2,] 0 0 0
#[3,] 1 1 1
#[4,] 2 2 2
I'm trying to create a function that will give me the value of a matrix once it has been raised to a power. This is what I've done so far:
A <- matrix(c(1,2,3,4,0,1,2,3,0,0,1,2,0,0,0,1),nrow=4,ncol=4)
power <- function(A,n){
+ if(n == 0){
+ return(diag(4))
+ }else{
+ return(A%*%A^(n-1))
+ }
+ }
OUTCOME:
> power(A,4)
[,1] [,2] [,3] [,4]
[1,] 1 0 0 0
[2,] 10 1 0 0
[3,] 46 10 1 0
[4,] 146 46 10 1
This is giving a different value from what my calculator gets and I'm trying to figure what I'm doing wrong. Any help is appreciated!
We could use %^% from library(expm)
library(expm)
A%*%(A%^%3)
Using this in a function
power <- function(A,n){
if(n == 0){
return(diag(4))
}else{
return(A%*%(A%^%(n-1)))
}
}
power(A,4)
# [,1] [,2] [,3] [,4]
#[1,] 1 0 0 0
#[2,] 8 1 0 0
#[3,] 36 8 1 0
#[4,] 120 36 8 1
According to the description in ?matpow
Compute the k-th power of a matrix. Whereas ‘x^k’ computes
element wise powers, ‘x %^% k’ corresponds to k - 1 matrix
multiplications, ‘x %% x %% ... %*% x’.
Or a base R option is Reduce with %*% (but this would be slow compared to %^%.
Reduce(`%*%`,replicate(4, A, simplify=FALSE))
In a function,
power1 <- function(A,n){
if(n == 0){
return(diag(4))
}else{
Reduce(`%*%`,replicate(n, A, simplify=FALSE))
}
}
power1(A,4)
# [,1] [,2] [,3] [,4]
#[1,] 1 0 0 0
#[2,] 8 1 0 0
#[3,] 36 8 1 0
#[4,] 120 36 8 1
You have a problem with the way you are computing your matrix product. I use a while loop inside your power() function instead. It simply multiples the input matrix against itself n times and then returns the result. Here is a base R solution which is a continuation of the direction in which you were already going.
A <- matrix(c(1,2,3,4,0,1,2,3,0,0,1,2,0,0,0,1),nrow=4,ncol=4)
power <- function(A,n){
B <- diag(nrow(A))
if (n == 0) {
return(diag(nrow(A)))
} else {
while (n > 0) {
B <- A%*%B
n <- n - 1
}
return(B)
}
}
> power(A, 4)
[,1] [,2] [,3] [,4]
[1,] 1 0 0 0
[2,] 8 1 0 0
[3,] 36 8 1 0
[4,] 120 36 8 1
I assume you want to make the muliplication of the matrix.You have to first make the multiply the matrix and then try to multiply them using the same powers as you want ,so you can do two things
Write code to multiply the matrix .
Loop the code to multiply.
I am looking for an easier way to do the following:
m <- matrix(0, nrow=3, 3)
v <- c(1, 3, 2)
for (i in 1:nrow(m)) {
m[[i, v[i]]] = 1
}
The above code creates the following index matrix:
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 0 1
[3,] 0 1 0
There surely must be a better way to do this?!
One way to do it without pre-defining the matrix would be to use outer:
num.col <- 3
outer(v, seq_len(num.col), "==") * 1
# [,1] [,2] [,3]
# [1,] 1 0 0
# [2,] 0 0 1
# [3,] 0 1 0
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)
))
This question already has answers here:
How to replace non-diagonal elements in a matrix?
(6 answers)
Closed 9 years ago.
Okay, I asked this question earlier but I got bashed (deservedly) for not specifying anything and showing no sign of previous attempt. So let me try again..
I'm using R, and I have a 463✕463 matrix. What I would like to do is to replace all elements other than the diagonal ones (X11, X22, X33,...,Xjj) with zero.
E.g. I want:
[1 4 5
2 3 5
3 9 8]
to be:
[1 0 0
0 3 0
0 0 8]
When I use the diag() function, it simply gives me a column vector of the diagonal values. I imagine I can use the replace() function somehow combined with a "if not diagonal" logic...but I am lost.
And yes, as some here have guessed, I am probably much younger than many people here and am completely new at this...so please put me in the right direction. Really appreciate all your help!
In R, the diag method has two functions.
It returns the diagonal of a matrix. I.e.
m <- matrix(1:9, ncol=3)
m
# [,1] [,2] [,3]
# [1,] 1 4 7
# [2,] 2 5 8
# [3,] 3 6 9
diag(m)
# [1] 1 5 9
It can construct a diagonal matrix.
diag(1:3)
# [,1] [,2] [,3]
# [1,] 1 0 0
# [2,] 0 2 0
# [3,] 0 0 3
So in your case, extract the diagonal from your existing matrix and supply it to diag:
diag(diag(m))
# [,1] [,2] [,3]
# [1,] 1 0 0
# [2,] 0 5 0
# [3,] 0 0 9
using outer
You can use the following to compute a logical matrix which describes the non-diagonal entries of a n×n matrix:
outer(1:n, 1:n, function(i,j) i!=j)
Applied to your example:
> m <- matrix(c(1,2,3,4,3,9,5,5,8),ncol=3)
> m
[,1] [,2] [,3]
[1,] 1 4 5
[2,] 2 3 5
[3,] 3 9 8
> m[outer(1:3, 1:3, function(i,j) i!=j)] <- 0
> m
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 3 0
[3,] 0 0 8
using triangles
A possible alternative would be combining the two triangles on either side of the diagonal. In this case, you use the matrix m itself as input to determine the size.
upper.tri(m) | lower.tri(m)
Applied to your use case:
> m[upper.tri(m) | lower.tri(m)] <- 0
It seems you already got this answer in response to your original post…
m[ col(m)==row(m) ] <- 0
> m <- matrix(1:9, 3)
> m[ col(m)==row(m) ]
[1] 1 5 9
> m[ col(m)!=row(m) ] <- 0
> m
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 5 0
[3,] 0 0 9