subset a matrix, and get NA if index is not valid - r

I am trying to subset a matrix to always get a 3*3 matrix.
For example, the matrix being subset is a<-matrix(1:15,3,5), usually when I subset it using a[0:2,0:2], I get:
[,1] [,2]
[1,] 1 4
[2,] 2 5
But I want to get something like:
[,1] [,2] [,3]
[1,] NA NA NA
[2,] NA 1 4
[3,] NA 2 5

Force all your 0's to NAs when you select, as well as any 'out-of-bounds' values:
ro <- 0:2
co <- 0:2
a[replace(ro,ro == 0 | ro > nrow(a),NA),
replace(co,co == 0 | co > ncol(a),NA)]
# [,1] [,2] [,3]
#[1,] NA NA NA
#[2,] NA 1 4
#[3,] NA 2 5
This will even work with combinations of the parts you want missing:
ro <- c(1,0,2)
co <- 0:2
a[replace(ro,ro == 0 | ro > nrow(a),NA),
replace(co,co == 0 | co > ncol(a),NA)]
# [,1] [,2] [,3]
#[1,] NA 1 4
#[2,] NA NA NA
#[3,] NA 2 5

You could create your own padding function to fill in space less than 3x3 by NA values
padmatrix <- function(a, dim=c(3,3)) {
stopifnot(all(dim(a)<=dim))
cbind(rep(NA,dim[2]-ncol(a)), rbind(rep(NA,dim[1]-nrow(a)), a))
}
padmatrix(a[1:2, 1:2])
# [,1] [,2] [,3]
# [1,] NA NA NA
# [2,] NA 1 4
# [3,] NA 2 5

Related

Access (and fill) different rows in array

Let's say I have a 3-dimensional array:
a <- array(dim = c(3, 2, 3))
and a vector with indices for the 1st dimension:
ind <- c(1,2,3)
Now I want to put a number (e.g. 1) into the rows (ind) across 2nd and 2rd dimension.
a[ind,,] <- matrix(1, ncol = 2, nrow = length(ind))
clearly does not work! A loop would work, however is there a better solution?
The result should be:
, , 1
[,1] [,2]
[1,] 1 1
[2,] NA NA
[3,] NA NA
, , 2
[,1] [,2]
[1,] NA NA
[2,] 1 1
[3,] NA NA
, , 3
[,1] [,2]
[1,] NA NA
[2,] NA NA
[3,] 1 1
Using mapply.
mapply(function(x, y) {a[x,,y] <<- 1;a}, ind, ind)
a
# , , 1
#
# [,1] [,2]
# [1,] 1 1
# [2,] NA NA
# [3,] NA NA
#
# , , 2
#
# [,1] [,2]
# [1,] NA NA
# [2,] 1 1
# [3,] NA NA
#
# , , 3
#
# [,1] [,2]
# [1,] NA NA
# [2,] NA NA
# [3,] 1 1
Or, for this specific case where x and y is the same, just:
sapply(ind, function(x) {a[x,,x] <<- 1;a})
Note: If you find the console output unnecessary wrap an invisible() around the code.
Another alternative that replaces everything in one step. It takes advantage of ['s operations when its argument is a matrix, each column indexing on a dimension of the array.
To confirm that it is putting values where we intend, I'll modify the replacement matrix to be 1:6.
# original data
a <- array(dim = c(3, 2, 3))
# the replacement matrix
r <- matrix(1:6, ncol = 2, nrow = length(ind))
# this will be what we index `a` on
m <- expand.grid(ind, seq_len(dim(a)[2]))
m$Var3 <- m$Var1 # repeat `ind` in the third dimension
m
# Var1 Var2 Var3
# 1 1 1 1
# 2 2 1 2
# 3 3 1 3
# 4 1 2 1
# 5 2 2 2
# 6 3 2 3
And the replacement:
a[as.matrix(m)] <- r
a
# , , 1
# [,1] [,2]
# [1,] 1 4
# [2,] NA NA
# [3,] NA NA
# , , 2
# [,1] [,2]
# [1,] NA NA
# [2,] 2 5
# [3,] NA NA
# , , 3
# [,1] [,2]
# [1,] NA NA
# [2,] NA NA
# [3,] 3 6

Multiplication of matrices with NA values

If I have 2 square Matrices with random NA values, for example:
Matrix A:
1 2 3
1 5 NA 7
2 NA 3 8
3 NA 4 5
Matrix B:
1 2 3
1 NA 8 NA
2 2 5 9
3 NA 4 3
What is the best way to multiply them? Would changing NA values to 0 give a different result of the dot product?
NAs will be ignored:
## Dummy matrices
mat1 <- matrix(sample(1:9, 9), 3, 3)
mat2 <- matrix(sample(1:9, 9), 3, 3)
## Adding NAs
mat1[sample(1:9, 4)] <- NA
mat2[sample(1:9, 4)] <- NA
mat1
# [,1] [,2] [,3]
#[1,] 9 NA 3
#[2,] 2 NA NA
#[3,] NA 1 8
mat2
# [,1] [,2] [,3]
#[1,] NA NA 4
#[2,] NA 9 3
#[3,] NA 7 1
mat1 * mat2
# [,1] [,2] [,3]
#[1,] NA NA 12
#[2,] NA NA NA
#[3,] NA 7 8
mat1 %*% mat2
# [,1] [,2] [,3]
#[1,] NA NA NA
#[2,] NA NA NA
#[3,] NA NA NA
In this case the dot product results in only NAs because there are no operations that does not involve an NA. Different matrices can lead to different results.

From tree list to a matrix in R

Apologies, if the question is too basic. What would be an effective approach/idea (in R) to convert
list(c(1), c(1,2), c(1,2,3), c(1,2,3,4))
to square matrix form
[,1] [,2] [,3] [,4]
[1,] 1 NA NA NA
[2,] 1 2 NA NA
[3,] 1 2 3 NA
[4,] 1 2 3 4
I suppose there is some quick dynamic way to append just the right number of NA values and then convert to a matrix.
Naturally, the size of the (square) matrix can change).
Thanks in advance for your time.
You can use
## create the list
x <- Map(":", 1, 1:4)
ml <- max(lengths(x))
do.call(rbind, lapply(x, "length<-", ml))
# [,1] [,2] [,3] [,4]
# [1,] 1 NA NA NA
# [2,] 1 2 NA NA
# [3,] 1 2 3 NA
# [4,] 1 2 3 4
Or you could do
library(data.table)
as.matrix(unname(rbindlist(lapply(x, as.data.frame.list), fill = TRUE)))
# [,1] [,2] [,3] [,4]
# [1,] 1 NA NA NA
# [2,] 1 2 NA NA
# [3,] 1 2 3 NA
# [4,] 1 2 3 4
And one more for good measure ... Fore!
m <- stringi::stri_list2matrix(x, byrow = TRUE)
mode(m) <- "numeric"
m
# [,1] [,2] [,3] [,4]
# [1,] 1 NA NA NA
# [2,] 1 2 NA NA
# [3,] 1 2 3 NA
# [4,] 1 2 3 4

create new matrix with new dimension and omitting NA values

I have a matrix with some NA values
for example:
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 NA 8 11
[3,] 3 6 NA 12
I want to create new matrix with data from my matrix above with new dimension and no NA value. (it is ok to have NA only some last elements)
something like:
[,1] [,2] [,3]
[1,] 1 6 11
[2,] 2 7 12
[3,] 3 8 NA
[4,] 4 10 NA
I would appreciate if anyone can help me.
Thanks
Something like this as well:
m <- matrix(1:12, nc=4)
m[c(5, 9)] <- NA
matrix(c(na.omit(c(m)), rep(NA, sum(is.na(m)))), nrow=4)
m <- matrix(1:12, nc=4)
m[c(5, 9)] <- NA
# create an array of the appropriate class and dimension (filled with NA values)
dims <- c(4, 3)
md <- array(m[0], dim=dims)
# replace first "n" values with non-NA values from m
nonNAm <- na.omit(c(m))
md[seq_along(nonNAm)] <- nonNAm
md
# [,1] [,2] [,3]
# [1,] 1 6 11
# [2,] 2 7 12
# [3,] 3 8 NA
# [4,] 4 10 NA
Yet another attempt. This will keep the order of the values in column order as a matrix usually would. E.g.:
mat <- matrix(c(1,2,3,4,NA,6,7,8,NA,10,11,12),nrow=3)
array(mat[order(is.na(mat))],dim=dim(mat))
# [,1] [,2] [,3] [,4]
#[1,] 1 4 8 12
#[2,] 2 6 10 NA
#[3,] 3 7 11 NA
Now change a value to check it doesn't affect the ordering.
mat[7] <- 20
array(mat[order(is.na(mat))],dim=dim(mat))
# [,1] [,2] [,3] [,4]
#[1,] 1 4 8 12
#[2,] 2 6 10 NA
#[3,] 3 20 11 NA
You can then specify whatever dimensions you feel like to the dim= argument:
array(mat[order(is.na(mat))],dim=c(4,3))
# [,1] [,2] [,3]
#[1,] 1 6 11
#[2,] 2 20 12
#[3,] 3 8 NA
#[4,] 4 10 NA
This is fairly straightforward if you want to preserve order column-wise or row-wise.
originalMatrix <- matrix(c(1,2,3,4,NA,6,7,8,NA,10,11,12),nrow=3)
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 NA 8 11
[3,] 3 6 NA 12
newMatrixNums <- originalMatrix[!is.na(originalMatrix)]
[1] 1 2 3 4 6 7 8 10 11 12
Pad with NA:
newMatrixNums2 <- c(newMatrixNums,rep(NA,2))
Column-wise:
matrix(newMatrixNums2,nrow=3)
[,1] [,2] [,3] [,4]
[1,] 1 4 8 12
[2,] 2 6 10 NA
[3,] 3 7 11 NA
Row-wise:
matrix(newMatrixNums2,nrow=3,byrow=T)
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 6 7 8 10
[3,] 11 12 NA NA
Here's one way:
# Reproducing your data
m <- matrix(1:12, nc=4)
m[c(5, 9)] <- NA
# Your desired dimensions
dims <- c(4, 3)
array(c(na.omit(c(m)), rep(NA, prod(dims) - length(na.omit(c(m))))), dim=dims)
# [,1] [,2] [,3]
# [1,] 1 6 11
# [2,] 2 7 12
# [3,] 3 8 NA
# [4,] 4 10 NA
This can do the job but dunno whether it is a good way.
list1 <- m[m]
list2 <- m[!is.na(m)]
element1 <- list2
element2 <- rep(NA, (length(list1)-length(list2)))
newm <- matrix(c(element1,element2), nrow=4)
If you increase the length of a numeric vector with length(x)<- without assigning values to the new elements, the new values are given NA as their value. So length(M2) <- length(M) takes the shorter M2 vector and makes it the same length as M by adding NA values to the new elements.
## original
> (M <- matrix(c(1:4,NA,6:8,NA,10:12), nrow = 3))
# [,1] [,2] [,3] [,4]
# [1,] 1 4 7 10
# [2,] 2 NA 8 11
# [3,] 3 6 NA 12
## new
> M2 <- M[!is.na(M)]; length(M2) <- length(M)
> matrix(M2, ncol(M))
# [,1] [,2] [,3]
# [1,] 1 6 11
# [2,] 2 7 12
# [3,] 3 8 NA
# [4,] 4 10 NA

In R how to control the cycling direction of values when copying in an array?

I would like to copy some values across rows but the default seems to be cycling over columns, is there an elegant way to achieve what I want ?
The following code I have is:
> w = array(NA,dim=c(4,2))
> w
[,1] [,2]
[1,] NA NA
[2,] NA NA
[3,] NA NA
[4,] NA NA
> w[2:4,] = c(2,3)
> w
[,1] [,2]
[1,] NA NA
[2,] 2 3
[3,] 3 2
[4,] 2 3
But I would like the values to be cycled over rows to obtain:
[,1] [,2]
[1,] NA NA
[2,] 2 3
[3,] 2 3
[4,] 2 3
You can write a new transposed assignment function:
`t<-` <- function(x, value)
{
t(matrix(value, nrow=ncol(x), ncol=nrow(x)))
}
Result:
> w = array(NA,dim=c(4,2))
> t(w[2:4,]) = c(2,3)
> w
[,1] [,2]
[1,] NA NA
[2,] 2 3
[3,] 2 3
[4,] 2 3
Create the matrix row-wise, then assign it:
w[2:4, ] <- matrix(c(2,3), nrow=3, ncol=2, byrow=TRUE)
Another elegant way :-)
w[2:4,] <- rep(c(2,3),each=length(2:4))
[,1] [,2]
[1,] NA NA
[2,] 2 3
[3,] 2 3
[4,] 2 3
w[2:4, ] <- matrix(c(2,3),nrow=1)[ rep(1,3), ]

Resources