Keep one maximum value per row in a matrix in R - r

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

Related

Calculations within a matrix with internal, references that are anchored to columns within the matrix in R

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

Create reducible matrices, perhaps with diag()

I have a few vectors that I would like to arrange into square matrices of the same dimensions for future multiplication. Some vectors are shorters than others so I would like to add zeros to the shorters ones so that all the resulting matrices are of the same dimension.
I tried to add 0 to the tail of the shorter vectors but I haven't been able to generate the reducible matrices that I want. Below are some pseudo data. Thank you for your time!
seq_a <- rep(1,4)
seq_b <- rep(1,3)
matA <- diag(seq_a)
matB <- matrix(c(diag(seq_b),0),nrow=4,ncol = 4)
[,1] [,2] [,3] [,4]
[1,] 1 1 1 0
[2,] 0 0 0 0
[3,] 0 0 1 1
[4,] 0 0 0 0
Warning message:
In matrix(c(diag(seq_c), 0), nrow = 4, ncol = 4) :
data length [10] is not a sub-multiple or multiple of the number of rows [4]
The desired matB should be
[,1] [,2] [,3] [,4]
[1,] 1 0 0 0
[2,] 0 1 0 0
[3,] 0 0 1 0
[4,] 0 0 0 0
That is just a typo: you should first pad the vector, and then convert it to a diagonal matrix.
matB <- diag( c(seq_b,0) )

Filling a matrix in R

I am trying to fill some rows of a (500,2) matrix with the row vector (1,0) using this code, last line is to verify the result:
data<-matrix(ncol=2,nrow=500)
data[41:150,]<-matrix(c(1,0),nrow=1,ncol=2,byrow=TRUE)
data[41:45,]
But the result is
> data[41:45,]
[,1] [,2]
[1,] 1 1
[2,] 0 0
[3,] 1 1
[4,] 0 0
[5,] 1 1
instead of
> data[41:45,]
[,1] [,2]
[1,] 1 0
[2,] 1 0
[3,] 1 0
[4,] 1 0
[5,] 1 0
(1) What am I doing wrong?
(2) Why aren't the row indices in the result 41, 42, 43, 44 and 45?
You're trying to fill a part of the matrix, so the block you're trying to drop in there should be of the right size:
data[41:150,]<-matrix(c(1,0),nrow=110,ncol=2,byrow=TRUE)
# nrow = 110, instead of 1 !!!!
Otherwise your piece-to-be-added will be reverted to vector and added columnwise. Try, for example, this:
data[41:150,] <- matrix(c(1,2,3,4,5), nrow=5, ncol=2, byrow=TRUE)
data[41:45,]
[,1] [,2]
[1,] 1 1
[2,] 3 3
[3,] 5 5
[4,] 2 2
[5,] 4 4
Can one complain? Yes, and now. No, because R behaves as documented (matrices are vectors with dimension attributes, and recycling works on vectors). Yes, because although recycling can be convenient, it may create false expectations.
Why aren't row indices 41,42,43,... ? I don't know, that's just the way matrices and vectors behave.
> (1:10)[5:6]
[1] 5 6
(Notice there's [1] in the output, not [5].)
Data frames behave differently, so you would see the original line numbers for slices:
as.data.frame(data)[45:50,]
It will be cleaner to just do this column-wise:
data[41:150, 1L] = 1
data[41:150, 2L] = 0
You could also accomplish this in one line with matrix indexing like so:
data[cbind(rep(41:150, each = 2L), 1:2)] = 1:0
You could use rep.
data[41:150,] <- rep(1:0, each=150-41+1)
#> data[41:45,]
# [,1] [,2]
#[1,] 1 0
#[2,] 1 0
#[3,] 1 0
#[4,] 1 0
#[5,] 1 0
I think MichaelChirico approach is the cleanest/savest to use.

Subtract ith value of a vector from non zero values of the ith row of a sparse matrix in R

I want to subtract ith value of the vector from non zero values of the ith row of a sparse matrix for e.g.
[,1] [,2] [,3] [,4]
[1,] 0 0 4 0
[2,] 0 5 0 3
[3,] 1 2 0 0
and here is the vector that i am trying to subtract:
[1] 1 2 3
so what i need in the end is:
[,1] [,2] [,3] [,4]
[1,] 0 0 3 0
[2,] 0 3 0 1
[3,] -2 -1 0 0
I have tried this using apply but haven't been able to figure the problem out, it does not return me quite what i want. The dimensions of the matrix are too large and I do not want to use loops. Thanks and regards.
Since subtracting a vector from a matrix is performed column-wise, mat-vec does the necessary subtraction. Since you only want to use this when the original matrix was non-zero (and return 0 for the elements that were originally 0), you could multiply by mat != 0, which is a 1/0 (TRUE/FALSE) matrix stating whether the original element was non-zero.
(mat - vec) * (mat != 0)
# [,1] [,2] [,3] [,4]
# [1,] 0 0 3 0
# [2,] 0 3 0 1
# [3,] -2 -1 0 0
If you instead wanted to do it for a sparse matrix:
library(Matrix)
(mat <- sparseMatrix(i=c(3, 2, 3, 1, 2), j=c(1, 2, 2, 3, 4), x=c(1, 5, 2, 4, 3)))
# 3 x 4 sparse Matrix of class "dgCMatrix"
# [1,] . . 4 .
# [2,] . 5 . 3
# [3,] 1 2 . .
vec <- c(1, 2, 3)
mat#x <- mat#x - vec[mat#i+1]
mat
# 3 x 4 sparse Matrix of class "dgCMatrix"
# [1,] . . 3 .
# [2,] . 3 . 1
# [3,] -2 -1 . .

Conditional deleting rows in a matrix

I have a matrix with 3 columns. The 1. column has either the value 1 or 0 in the rows. I want to delete all the rows in the matrix, where the 1. column is equal to zero (or keep the rows containing ones).
Thanks.
So, say that you have this matrix:
A= matrix(c(1, 2, 3, 0, 3, 5, 1, 3, 8),3,3, byrow=T)
The following command will give you a vector of TRUE/FALSE for each row, depending on whether the 1st column is 1 or not:
A[,1]==1
You can then select only those rows like this:
FILTERED = A[A[,1]==1,]
And you'll then find what you ask for in FILTERED
Try this:
#dummy matrix
x <- matrix(rep(c(1,0,1),4),ncol=3)
x
# [,1] [,2] [,3]
# [1,] 1 0 1
# [2,] 0 1 1
# [3,] 1 1 0
# [4,] 1 0 1
#keep rows where 1st column equals to 1
x[x[,1] == 1,]
# [,1] [,2] [,3]
# [1,] 1 0 1
# [3,] 1 1 0
# [4,] 1 0 1

Resources