I need to access and assign single slots of an m*n matrix inside a for loop. The code so far:
rowCount <- 9
similMatrix = matrix(nrow = rowCount - 1, ncol = rowCount)
show(similMatrix)
for(i in (rowCount - 1)){
for (j in rowCount)
if (i == j){
similMatrix[i == j] <- 0;
}
}
show(similMatrix)
so if i = j the NA value in the matrix needs to be replaced with 0.
You want the function diag<-
m <- matrix(1:12, nrow=3)
m
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
diag(m) <- 0
m
[,1] [,2] [,3] [,4]
[1,] 0 4 7 10
[2,] 2 0 8 11
[3,] 3 6 0 12
For the purpose of setting the "diagonal" elements to zero you have already been given an answer but I wonder if you were hoping for something more general. The reasons for lack of success with that code were two-fold: the construction of your indices were flawed and the indexing was wrong. This would have succeeded:
for(i in 1:(rowCount - 1)){ # need an expression that retruns a sequence
for (j in 1:rowCount) # ditto
if (i == j){
similMatrix[i,j] <- 0; # need to index the matrix with two element if using i,j
}
}
#----------
> show(similMatrix)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,] 0 NA NA NA NA NA NA NA NA
[2,] NA 0 NA NA NA NA NA NA NA
[3,] NA NA 0 NA NA NA NA NA NA
[4,] NA NA NA 0 NA NA NA NA NA
[5,] NA NA NA NA 0 NA NA NA NA
[6,] NA NA NA NA NA 0 NA NA NA
[7,] NA NA NA NA NA NA 0 NA NA
[8,] NA NA NA NA NA NA NA 0 NA
But resorting to loops in R is generally considered a last resort (sometimes for the wrong reasons.) There is a much more compact way of doing the same "loop" operation and it generalizes more widely than just setting the diagonal.
similMatrix[ row(similMatrix) == col(similMatrix) ] <- 0
> similMatrix
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,] 0 NA NA NA NA NA NA NA NA
[2,] NA 0 NA NA NA NA NA NA NA
[3,] NA NA 0 NA NA NA NA NA NA
[4,] NA NA NA 0 NA NA NA NA NA
[5,] NA NA NA NA 0 NA NA NA NA
[6,] NA NA NA NA NA 0 NA NA NA
[7,] NA NA NA NA NA NA 0 NA NA
[8,] NA NA NA NA NA NA NA 0 NA
If you wanted to set the subdiagonal to zero you could just use:
similMatrix[ row(similMatrix)-1 == col(similMatrix) ] <- 0
You can avoid generating the extra row and col matrices using this:
mind <- min( dim(similMatrix) )
# avoid going outside dimensions if not symmetric
similMatrix[ cbind( seq(maxd),seq(maxd) ) <- 0
Related
I am trying to produce a matrix of variable dimensions of the form below (i.e. integers increasing by 1 at a time, with a lower triangle of NAs)
NA 1 2 3 4
NA NA 5 6 7
NA NA NA 8 9
NA NA NA NA 10
NA NA NA NA 11
I have used the below code
sample_vector <- c(1:(total_nodes^2))
sample_matrix <- matrix(sample_vector, nrow=total_nodes, byrow=FALSE)
sample_matrix[lower.tri(sample_matrix, diag = TRUE)] <- NA
However the matrix I get with this method is of the form:
NA 2 3 4 5
NA NA 8 9 10
NA NA NA 14 15
NA NA NA NA 20
NA NA NA NA 25
How about this
total_nodes <- 5
sample_matrix <- matrix(NA, nrow=total_nodes, ncol=total_nodes)
sample_matrix[lower.tri(sample_matrix)]<-1:sum(lower.tri(sample_matrix))
sample_matrix <- t(sample_matrix)
sample_matrix
# [,1] [,2] [,3] [,4] [,5]
# [1,] NA 1 2 3 4
# [2,] NA NA 5 6 7
# [3,] NA NA NA 8 9
# [4,] NA NA NA NA 10
# [5,] NA NA NA NA NA
I'm using the diag function to construct a matrix and upper.tri to turn it into a "target" aas well as a logical indexing tool:
upr5 <- upper.tri(diag(5))
upr5
upr5[upr5] <- 1:sum(upr5)
upr5[upr5==0] <- NA # would otherwise have been zeroes
upr5
[,1] [,2] [,3] [,4] [,5]
[1,] NA 1 2 4 7
[2,] NA NA 3 5 8
[3,] NA NA NA 6 9
[4,] NA NA NA NA 10
[5,] NA NA NA NA NA
I'm trying to fill the columns of an index matrix with samples from 1:whatever using a for loop. The purpose of this is for a bootstrap coding problem. The issue I'm getting is that the for loop wont run correctly once it reaches a number that is not a multiple of the row length. For some reason it thinks I want an equal representation of number in each column. How do I get this to stop?
index.mat=matrix(NA,nr=12,nc=10,byrow=FALSE)
for(i in 1:5)
{
index.mat[,i] <- sample(1:i, i, replace=TRUE)
print(index.mat)
}
will print
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 1 2 1 NA NA NA NA NA NA
[2,] 1 1 2 4 NA NA NA NA NA NA
[3,] 1 1 2 1 NA NA NA NA NA NA
[4,] 1 1 2 2 NA NA NA NA NA NA
[5,] 1 1 2 1 NA NA NA NA NA NA
[6,] 1 1 2 4 NA NA NA NA NA NA
[7,] 1 1 2 1 NA NA NA NA NA NA
[8,] 1 1 2 2 NA NA NA NA NA NA
[9,] 1 1 2 1 NA NA NA NA NA NA
[10,] 1 1 2 4 NA NA NA NA NA NA
[11,] 1 1 2 1 NA NA NA NA NA NA
[12,] 1 1 2 2 NA NA NA NA NA NA
as the final matrix before giving the error
Error in index.mat[, i] <- sample(1:i, i, replace = TRUE) :
number of items to replace is not a multiple of replacement length
Just use sample(i, size = 12, replace = TRUE).
Your LHS is index.mat[,i] which has length 12.
Your RHS is sample(1:i, i, replace = TRUE), which has length i.
By nature, R will recycle the RHS when the lengths don't match up -- this means, when i=2, your RHS is length 2 and it will simply be repeated 6 times to match the LHS length 12.
In this particular case, if the RHS length isn't a divisor of the LHS length, you get an error -- which happens first when, you guessed it, i=5 (since 1, 2, 3, and 4 all divide 12 evenly).
I need to insert a vector diagonally into a matrix on an arbitrary place. I know how to insert a vector vertically or horizontally but I can't do it diagonally.
I have:
A <- matrix(nrow=6,ncol=6)
b <- c(1:4)
The desired result (if I want to insert the vector in the position A[3,2]), would be:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] NA NA NA NA NA NA
[2,] NA NA NA NA NA NA
[3,] NA 1 NA NA NA NA
[4,] NA NA 2 NA NA NA
[5,] NA NA NA 3 NA NA
[6,] NA NA NA NA 4 NA
Also, I want to be able to insert the vector to get this matrix (starting from A[4,1]):
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] NA NA NA 4 NA NA
[2,] NA NA 3 NA NA NA
[3,] NA 2 NA NA NA NA
[4,] 1 NA NA NA NA NA
[5,] NA NA NA NA NA NA
[6,] NA NA NA NA NA NA
Here's one possibility (you could probably wrap it up into a function)
indx <- 0:(length(b) - 1) # Create an index
Frow <- 3 ; Fcol <- 2 #initiate rows/cols
A[cbind(Frow + indx, Fcol + indx)] <- b
A
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] NA NA NA NA NA NA
# [2,] NA NA NA NA NA NA
# [3,] NA 1 NA NA NA NA
# [4,] NA NA 2 NA NA NA
# [5,] NA NA NA 3 NA NA
# [6,] NA NA NA NA 4 NA
For your second output (Assuming A matrix is all NAs again)
Frow <- 4 ; Fcol <- 1
A[cbind(Frow - indx, Fcol + indx)] <- b
A
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] NA NA NA 4 NA NA
# [2,] NA NA 3 NA NA NA
# [3,] NA 2 NA NA NA NA
# [4,] 1 NA NA NA NA NA
# [5,] NA NA NA NA NA NA
# [6,] NA NA NA NA NA NA
You can use this function:
insert.diag <- function(A,b,start=c(1,1),dir=c(1,1)) {
sq <- seq_along(b)-1
indices <- sapply(1:2,function(i) start[i] + dir[i]*sq)
stopifnot(all(indices>0))
stopifnot(all(indices[,1]<=nrow(A)))
stopifnot(all(indices[,2]<=ncol(A)))
A[indices] <- b
A
}
Some examples of use:
A <- matrix(nrow=6,ncol=6)
b <- c(1:4)
> insert.diag(A,b,c(1,6),c(1,-1))
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] NA NA NA NA NA 1
[2,] NA NA NA NA 2 NA
[3,] NA NA NA 3 NA NA
[4,] NA NA 4 NA NA NA
[5,] NA NA NA NA NA NA
[6,] NA NA NA NA NA NA
> insert.diag(A,b,c(6,6),c(-1,-1))
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] NA NA NA NA NA NA
[2,] NA NA NA NA NA NA
[3,] NA NA 4 NA NA NA
[4,] NA NA NA 3 NA NA
[5,] NA NA NA NA 2 NA
[6,] NA NA NA NA NA 1
> insert.diag(A,b,c(1,1),c(1,1))
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 NA NA NA NA NA
[2,] NA 2 NA NA NA NA
[3,] NA NA 3 NA NA NA
[4,] NA NA NA 4 NA NA
[5,] NA NA NA NA NA NA
[6,] NA NA NA NA NA NA
I have a large matrix which comprises 1,2 and missing (coded as NA) values. The matrix has 500000 rows by 10000 columns. There are approximately 0.05% 1- or 2-values, and the remaining values are NA.
I would like to reorder the rows and columns of the matrix so that the top left corner of the matrix comprises a relatively high number of 1s and 2s compared to the rest of the matrix. In other words, I would like to create a relatively datarich subset of the matrix, by reordering the matrix rows and columns.
Is there an efficient method of achieving this in R, perhaps using a library? I would also be interested in solutions in Python or Java, but I would prefer to perform this in R as it is the language that's most familiar to me.
I thought that there maybe a set of optimisation procedures that I could use as my working matrix is too large to do the reorganisation by eye.
I have reverted a set of edits so that the question remains consistent with the current answers.
Like this?
#some sparse data
set.seed(42)
p <- 0.0005
mat <- matrix(sample(c(1, 2, NA), 1e4, TRUE, c(p/2, p/2, 1-p)), ncol=50)
#order columns and rows by the number of NA values in them
mat <- mat[order(rowSums(is.na(mat))), order(colSums(is.na(mat)))]
#only show columns and rows containing non-NA values
mat[rowSums(!is.na(mat)) > 0, colSums(!is.na(mat)) > 0]
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] NA NA NA NA 2 NA
# [2,] NA NA NA NA NA 2
# [3,] NA NA 2 NA NA NA
# [4,] NA 1 NA NA NA NA
# [5,] 1 NA NA NA NA NA
# [6,] NA NA NA 2 NA NA
Something like this?
Rgames> bar
[,1] [,2] [,3] [,4] [,5]
[1,] NA NA NA NA NA
[2,] 1 NA NA NA 3
[3,] NA NA NA NA NA
[4,] 2 NA NA NA 4
[5,] NA NA NA NA NA
Rgames> rab<-bar[order(bar[,1]),]
Rgames> rab
[,1] [,2] [,3] [,4] [,5]
[1,] 1 NA NA NA 3
[2,] 2 NA NA NA 4
[3,] NA NA NA NA NA
[4,] NA NA NA NA NA
[5,] NA NA NA NA NA
Rgames> rab[,order(rab[1,])]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 NA NA NA
[2,] 2 4 NA NA NA
[3,] NA NA NA NA NA
[4,] NA NA NA NA NA
[5,] NA NA NA NA NA
EDIT, as Roland pointed out, in a more general situation that won't come close. Now, if one is allowed to 'jumble' the rows and columns, this would do it:
for(j in 1:nrow(mfoo)) mat[j,]<-mat[j,order(mat[j,])]
for(j in 1:ncol(mat)) mat[,j]<-mat[order(mat[,j]),j]
I suspect that's not what is desired, so I'll go off and think some more about ordering "criteria"
I have a large matrix which comprises 1,2 and missing (coded as NA) values. The matrix has 500000 rows by 10000 columns. There are approximately 0.05% 1- or 2-values, and the remaining values are NA.
I would like to reorder the rows and columns of the matrix so that the top left corner of the matrix comprises a relatively high number of 1s and 2s compared to the rest of the matrix. In other words, I would like to create a relatively datarich subset of the matrix, by reordering the matrix rows and columns.
Is there an efficient method of achieving this in R?
In particular, I'm interested in solutions where sorting by the number of non-NA values in each row and column is not sufficient to produce a dense corner.
In addition, I'll add a constraint. The size of the dense corner will be pre-defined.
In the following example, the goal is to reorder the rows and columns so that the top leftmost 3x3 submatrix is relatively dense (i.e. few or no NA values).
m1 <- matrix(c(rep(c(rep(NA, 3), rep(1, 7)), 1),
rep(c(rep(2, 3), rep(NA, 7)), 7),
rep(c(rep(NA, 3), rep(1, 7)), 2)
), nrow=10, byrow=TRUE)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] NA NA NA 1 1 1 1 1 1 1
[2,] 2 2 2 NA NA NA NA NA NA NA
[3,] 2 2 2 NA NA NA NA NA NA NA
[4,] 2 2 2 NA NA NA NA NA NA NA
[5,] 2 2 2 NA NA NA NA NA NA NA
[6,] 2 2 2 NA NA NA NA NA NA NA
[7,] 2 2 2 NA NA NA NA NA NA NA
[8,] 2 2 2 NA NA NA NA NA NA NA
[9,] NA NA NA 1 1 1 1 1 1 1
[10,] NA NA NA 1 1 1 1 1 1 1
The rows and columns are ordered by the number of non-NA values (using code from an answer below):
m1 <- m1[order(rowSums(is.na(m1))), order(colSums(is.na(m1)))]
However, this does not result in a dense 3x3 top leftmost corner:
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] NA NA NA 1 1 1 1 1 1 1
[2,] NA NA NA 1 1 1 1 1 1 1
[3,] NA NA NA 1 1 1 1 1 1 1
[4,] 2 2 2 NA NA NA NA NA NA NA
[5,] 2 2 2 NA NA NA NA NA NA NA
[6,] 2 2 2 NA NA NA NA NA NA NA
[7,] 2 2 2 NA NA NA NA NA NA NA
[8,] 2 2 2 NA NA NA NA NA NA NA
[9,] 2 2 2 NA NA NA NA NA NA NA
[10,] 2 2 2 NA NA NA NA NA NA NA
I thought that there maybe a set of optimisation procedures that I could implement as my working matrix is too large to do the reorganisation by eye.