Modifying empty matrix given matrix of positions and vector of values - r

Given the following setup:
> vals = matrix(nrow = 3,ncol = 4)
[,1] [,2] [,3] [,4]
[1,] NA NA NA NA
[2,] NA NA NA NA
[3,] NA NA NA NA
> position = matrix(c(4,2,1, 6,3,2, NA,NA,3, NA,NA,4), nrow = 3, ncol = 4)
[,1] [,2] [,3] [,4]
[1,] 1 4 NA NA
[2,] 2 3 NA NA
[3,] 1 2 3 4
> temp = c(10, 5, 8, 6, 9, 2, 4, 3)
I'm trying to populate vals with the values held in temp. However, the values must be placed in the spots given by position. Specifically, each row in position represents a row in vals, and the values represent the column in which the value must be placed.
For example, position[2,2] = 3. Since that's position's second row, the respective value must go into vals[2,3]. The final result would be:
[,1] [,2] [,3] [,4]
[1,] 10 NA NA 5
[2,] NA 8 6 NA
[3,] 9 2 4 3
This would be straightforward with for-loops, but can it be done without them?

We can use a row/column indexing by cbinding the row index (created with row, c -> convert the numeric index matrix to vector), with the column index by transposing the 'position', coerce it to vector (c), remove the NA elements (na.omit), extract the elements in 'vals' based on the indexes and assign (<-) to 'temp'
vals[na.omit(cbind(c(t(row(position))), c(t(position))))] <- temp
vals
# [,1] [,2] [,3] [,4]
#[1,] 10 NA NA 5
#[2,] NA 8 6 NA
#[3,] 9 2 4 3
data
position <- structure(c(1, 2, 1, 4, 3, 2, NA, NA, 3, NA, NA, 4), .Dim = 3:4)

Related

Shifting leading NA cells to the left, but NOT internal NAs in R

As a preface, I've noticed that there are at least 5 answers to a similar question, "How do I shift non-NA cells leftward." There are many good answers for this, and the zoo package has a na.locf() that does it well.
My particular issue is that I want to shift the cells to the right of the final leading NA leftward, replacing all leading NAs. This means that I need to retain "internal" and trailing NAs. Here's a small example with a matrix, but my real data is a large data.frame:
matrixtest[1, 1:3] <- NA
matrixtest[3, 1:2] <- NA
matrixtest[2, 3] <- NA
matrixtest[4, 2] <- NA
matrixtest
matrixresult <-matrix(4, ncol = 4, nrow = 4)
matrixresult[1, 2:4] <- NA
matrixresult[3, 3:4] <- NA
matrixresult[2, 3] <- NA
matrixresult[4, 2] <- NA
matrixresult
After manipulation the matrixtest original should look like the matrixresult
as such:
[,1] [,2] [,3] [,4]
[1,] NA NA NA 4
[2,] 4 4 NA 4
[3,] NA NA 4 4
[4,] 4 NA 4 4
> matrixresult
[,1] [,2] [,3] [,4]
[1,] 4 NA NA NA
[2,] 4 4 NA 4
[3,] 4 4 NA NA
[4,] 4 NA 4 4
Apologies if I've missed an applicable answer already. I've spent too much time on this seemingly simple problem.
We create an index based on the last column and reverse those rows
i1 <- is.na(matrixresult[, ncol(matrixresult)])
matrixresult[i1, ] <- t(apply(matrixresult[i1,], 1, rev))
-output
matrixresult
# [,1] [,2] [,3] [,4]
#[1,] NA NA NA 4
#[2,] 4 4 NA 4
#[3,] NA NA 4 4
#[4,] 4 NA 4 4
1) shiftLeft removes the NAs off the ends in its input x using na.trim giving y and then overwrites the beginning of a vector of NAs with that. apply that to every row and transpose that since apply results in the transpose of what we want.
library(zoo)
shiftLeft <- function(x, y = na.trim(x)) replace(NA * x, seq_along(y), y)
m <- t(apply(matrixtest, 1, shiftLeft))
# check
identical(m, matrixresult)
## [1] TRUE
2) An alternate which is a bit longer but only involves base R is:
shiftLeft2 <- function(x) {
ix <- which.max(!is.na(x))
replace(NA*x, seq_len(length(x) - ix + 1), x[ix:length(x)])
}
m2 <- t(apply(matrixtest, 1, shiftLeft2))
Note
We used the first matrix as input and the second to check against.
matrixtest <- structure(c(NA, 4, NA, 4, NA, 4, NA, NA, NA, NA, 4, 4, 4, 4,
4, 4), .Dim = c(4L, 4L))
matrixresult <- structure(c(4, 4, 4, 4, NA, 4, 4, NA, NA, NA, NA, 4, NA, 4, NA,
4), .Dim = c(4L, 4L))

Setting matrix values comparing to vector in R

I want to set NA's in every element of a matrix where the value in a column is greater than or equal to the value of a given vector. For example, I can create a matrix:
set.seed(1)
zz <- matrix(data = round(10L * runif(12)), nrow = 4, ncol = 3)
which gives for zz:
[,1] [,2] [,3]
[1,] 8 5 7
[2,] 6 5 1
[3,] 5 10 3
[4,] 9 1 9
and for the comparison vector (for example):
xx <- round(10L * runif(4))
where xx is:
[1] 6 3 8 2
if I perform this operation:
apply(zz,2,function(x) x >= xx)
I get:
[,1] [,2] [,3]
[1,] TRUE FALSE TRUE
[2,] TRUE TRUE FALSE
[3,] FALSE TRUE FALSE
[4,] TRUE FALSE TRUE
What I want is everywhere I have a TRUE element I want an NA and everywhere I have a FALSE I get the number in the zz matrix (e.g., manually ...):
NA 5 NA
NA NA 1
5 NA 3
NA 1 NA
I can cobble together some "for" loops to do what I want, but is there a vector-based way to do this??
Thanks for any tips.
You could simply do:
zz[zz>=xx] <- NA
# [,1] [,2] [,3]
#[1,] NA 5 NA
#[2,] NA NA 1
#[3,] 5 NA 3
#[4,] NA 1 NA
Here is one option to get the expected output. We get a logical matrix (zz >= xx), using NA^ on that returns NA for the TRUE values and 1 for the FALSE, then multiply it with original matrix 'zz' so that NA remains as such while the 1 changes to the corresponding value in 'zz'.
NA^(zz >= xx)*zz
# [,1] [,2] [,3]
#[1,] NA 5 NA
#[2,] NA NA 1
#[3,] 5 NA 3
#[4,] NA 1 NA
Or another option is ifelse
ifelse(zz >= xx, NA, zz)
data
zz <- structure(c(8, 6, 5, 9, 5, 5, 10, 1, 7, 1, 3, 9), .Dim = c(4L, 3L))
xx <- c(6, 3, 8, 2)

How to test whether a matrix is empty

I created an empty matrix by matrix(), when I need to test whether a given matrix is empty, How can I do that? I know that is.na(matrix()) is TRUE, but if given matrix is higher dimension, it cannot determine.
What I mean empty is element full of NA or NULL.
I'm guessing that you are just looking for all. Here's a small example:
M1 <- matrix(NA, ncol = 3, nrow = 3)
# [,1] [,2] [,3]
# [1,] NA NA NA
# [2,] NA NA NA
# [3,] NA NA NA
M2 <- matrix(c(1, rep(NA, 8)), ncol = 3, nrow = 3)
M2
# [,1] [,2] [,3]
# [1,] 1 NA NA
# [2,] NA NA NA
# [3,] NA NA NA
all(is.na(M1))
# [1] TRUE
all(is.na(M2))
# [1] FALSE

Selecting rows conditional on column value from multiple matrices

I have
mat1 = matrix(c(2, 4, 3, 6, 7, 8), nrow=2, ncol=3)
mat2 = matrix(c(5, 6, 7, 1, 2, 3), nrow=2, ncol=3)
mat3 = matrix(c(8, 5, 8, 6, 7, 9), nrow=2, ncol=3)
which gives me 3 matrices:
[,1] [,2] [,3]
[1,] 2 3 7
[2,] 4 6 8
[,1] [,2] [,3]
[1,] 5 7 2
[2,] 6 1 3
[,1] [,2] [,3]
[1,] 8 8 7
[2,] 5 6 9
What I would like to do is compare the three matrices per row per first column, and select the row of the matrix that has the highest value on the first column.
For example: in row 1 column 1, matrix3 has the highest value (8) compared to matrix1 (2) and matrix2 (5). In row 2 column 1, matrix2 has the highest value (6). I would like to create a new matrix that copies the row of the matrix that has that highest value, resulting in:
[,1] [,2] [,3]
[1,] 8 8 7 <- From mat3
[2,] 6 1 3 <- From mat2
I know how to get a vector with the highest values from column 1, but I cannot get the whole row of the matrix copied into a new matrix. I have:
mat <- (mat1[1,])
which just copies the first row of the first matrix
[1] 2 3 7
I can select which number is the maximum number:
max(mat1[,1],mat2[,1],mat3[,1])
[1] 8
But I cannot seem to combine the two to return a matrix with the whole row.
Getting the code to loop for each row will be no problem, but I cannot seem to get it to work for the first row and as such, I am missing the essential code. Any help would be greatly appreciated. Thank you.
Are you working interactively? Do you manipulate multiple matrices spread in your workspace? A straightforward answer to your problem could be:
#which matrices have the largest element of column 1 in each row?
max.col(cbind(mat1[, 1], mat2[, 1], mat3[, 1]))
#[1] 3 2
rbind(mat3[1, ], mat2[2, ]) #use the above information to get your matrix
# [,1] [,2] [,3]
#[1,] 8 8 7
#[2,] 6 1 3
On a more ganeral use-case, a way could be:
mat_ls = list(mat1, mat2, mat3) #put your matrices in a "list"
which_col = 1 #compare column 1
which_mats = max.col(do.call(cbind, lapply(mat_ls, function(x) x[, which_col])))
do.call(rbind, lapply(seq_along(which_mats),
function(i) mat_ls[[which_mats[i]]][i, ]))
# [,1] [,2] [,3]
#[1,] 8 8 7
#[2,] 6 1 3
Probably not the prettiest solution
temp <- rbind(mat1, mat2, mat3)
rbind(temp[c(T,F),][which.max(temp[c(T,F),][, 1]),],
temp[c(F,T),][which.max(temp[c(F,T),][, 1]),])
## [,1] [,2] [,3]
## [1,] 8 8 7
## [2,] 6 1 3
You may also try:
a2 <- aperm(simplify2array( mget(ls(pattern="mat"))),c(3,2,1)) #gets all matrices with name `mat`
t(sapply(1:(dim(a2)[3]), function(i) {x1 <- a2[,,i]; x1[which.max(x1[,1]),]}))
# [,1] [,2] [,3]
#[1,] 8 8 7
#[2,] 6 1 3

Separating and comparing complete cases and NA elements in a vector

I have a vector with numerical and NA elements.
For example,
data<-c(.4, -1, 1, NA, 8, NA, -.4)
data[complete.cases(data), ]
But what's the function to separate them into different vectors so I can compare them using graphs such as a boxplot and ECDF?
It's not clear what problem you are trying to solve. complete.cases creates a logical vector for selection (if you use it correctly.) You can negate it to get the other ones. You cannot address a vector as you attempted with [ , ] but if 'data' were a dataframe (or a matrix) that would have worked.
data<-c(.4, -1, 1, NA, 8, NA, -.4)
data[complete.cases(data) ]
#[1] 0.4 -1.0 1.0 8.0 -0.4
data[!complete.cases(data) ]
#[1] NA NA
If one is trying to select the non-NA items it might be easier to use !is.na(data) as the selection vector. This is a test case showing it works with matrices as well as data.frames:
> dat <- matrix( sample(c(1,2,NA), 12, rep=TRUE), 3)
> dat
[,1] [,2] [,3] [,4]
[1,] 1 1 1 1
[2,] NA NA 2 2
[3,] 1 NA 2 1
> dat[ complete.cases(dat), ]
[1] 1 1 1 1
> dat[ ! complete.cases(dat), ]
[,1] [,2] [,3] [,4]
[1,] NA NA 2 2
[2,] 1 NA 2 1

Resources