Select array entries based on 2D matrix values - r

I have a simple question that I seem to not be able to wrap my head around. I have a 3D array (an image stack) and I am trying to do a projection onto 2D array (e.g. a maximum intensity projection for an image stack). To do this, I have a matrix of indices which indicate the z-stack to use for each pixel.
For example, I have a 3D array which looks like this:
, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 5 7
[2,] 6 8
And a "selection matrix" which looks like this:
[,1] [,2]
[1,] 1 1
[2,] 2 2
The result of this selection should then be
[,1] [,2]
[1,] 1 3
[2,] 6 8
i.e. the matrix indicates from which "z-columns" of the array to extract the values.
I know this should be a stupid simple thing but I'm drawing a blank on how to do this. Thank you in advance!

One way to do this is to use multi-dimensional array indexing via cbind:
Here is your data and selection matrix:
d <- array(1:8,c(2,2,2))
selec <- matrix(c(1,2,1,2),2,2)
First construct a grid of your selection matrix indices:
selec.ind <- expand.grid(1:nrow(selec),1:ncol(selec))
Then use this with the selection matrix values to access d:
out <- matrix(d[cbind(selec.ind$Var1,selec.ind$Var2,as.vector(selec))], nrow(selec), ncol(selec))
## [,1] [,2]
##[1,] 1 3
##[2,] 6 8
Finally, reshape the result back to the size of the selection matrix.
This will work with any size selection matrix and any number of layers in z.

This only works for array with 2 third dimensions (dim=c(...,...,2))
The data:
ar=array(data=c(1,2,3,4,5,6,7,8),dim = c(2,2,2))
, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 5 7
[2,] 6 8
selec=matrix(c(1,2,1,2),nrow = 2,ncol = 2)
[,1] [,2]
[1,] 1 1
[2,] 2 2
We use ifelse
ifelse(selec==1,ar[,,1],ar[,,2])
[,1] [,2]
[1,] 1 3
[2,] 6 8

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

Repeat rows in a data frame according to a vector

I have a data frame and would like to repeat each row by each element in a pre defined vector.
for example if I have a matrix (I use matrix for example)
matrix(c(1,2,3,2,1,3),2)
[,1] [,2] [,3]
[1,] 1 3 1
[2,] 2 2 3
I would like this to return
matrix(c(1,1,2,2,3,3,2,2,1,1,3,3),4)
[,1] [,2] [,3]
[1,] 1 3 1
[2,] 1 3 1
[3,] 2 2 3
[4,] 2 2 3
if the vector was vec = c(2,2).
my vector has varying size elements. Sorry, I am new to coding.
Repeat over the row numbers. In your example:
base = matrix(c(1,2,3,2,1,3),2)
rows = 1:nrow(base)
index= rep(rows, c(2,2))
base[index,]

How to apply a function on every element of all elements in a list in R

I have a list containing matrices of the same size in R. I would like to apply a function over the same element of all matrices. Example:
> a <- matrix(1:4, ncol = 2)
> b <- matrix(5:8, ncol = 2)
> c <- list(a,b)
> c
[[1]]
[,1] [,2]
[1,] 1 3
[2,] 2 4
[[2]]
[,1] [,2]
[1,] 5 7
[2,] 6 8
Now I want to apply the mean function and would like to get a matrix like that:
[,1] [,2]
[1,] 3 5
[2,] 4 6
One conceptual way to do this would be to sum up the matrices and then take the average value of each entry. Try using Reduce:
Reduce('+', c) / length(c)
Output:
[,1] [,2]
[1,] 3 5
[2,] 4 6
Demo here:
Rextester
Another option is to construct an array and then use apply.
step 1: constructing the array.
Using the abind library and do.call, you can do this:
library(abind)
myArray <- do.call(function(...) abind(..., along=3), c)
Using base R, you can strip out the structure and then rebuild it like this:
myArray <- array(unlist(c), dim=c(dim(a), length(c)))
In both instances, these return the desired array
, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 5 7
[2,] 6 8
step 2: use apply to calculate the mean along the first and second dimensions.
apply(myArray, 1:2, mean)
[,1] [,2]
[1,] 3 5
[2,] 4 6
This will be more flexible than Reduce, since you can swap out many more functions, but it will be slower for this particular application.

Creating data frames from list of elements without element names [duplicate]

This question already has answers here:
The difference between bracket [ ] and double bracket [[ ]] for accessing the elements of a list or dataframe
(11 answers)
Closed 7 years ago.
I would like to create a separate dataframe from list of data elements of matrices. For example, I have the following list of matrix elements:-
> A[[1]]
$`up`
,, T+1
[,1] [,2] [,3]
[1,] 2 4 3
[2,] 1 5 7
$`down`
,, T+1
[,1] [,2] [,3]
[1,] 3 2 1
[2,] 2 4 2
$`right`
,,T+1
[,1] [,2] [,3]
[1,] 5 6 7
[2,] 9 2 3
Suppose that I want to create a separate list of data elements. I don't want the element names '$'up'/$'down'/$'right' to appear on my output. With the current code, every time I want to call the first matrix, I have to write the code as
A[[1]]$'up'[,,1] or A[[1]]$'down'[,,1] or A[[1]]$'right'[,,1]
Is it possible to create a separate list so that whenever I want to call it, it would be simpler without the elements name. For example, I just want to call A[[1]], whenever I want to call the first matrix, A[[2]] for the second matrix and so on. It will look something like this:-
> A[[1]]
[,1] [,2] [,3]
[1,] 2 4 3
[2,] 1 5 7
> A[[2]]
[,1] [,2] [,3]
[1,] 3 2 1
[2,] 2 4 2
> A[[3]]
[,1] [,2] [,3]
[1,] 5 6 7
[2,] 9 2 3
With your definition of A you can already access the i-th matrix via A[[i]], e.g.:
> A[[1]]
[,1] [,2] [,3]
[1,] 2 4 3
[2,] 1 5 7
Alternatively you can create a 3-dimensional array, where the third dimension indicates the number of the matrix:
B <- array(do.call("cbind", A), c(2,3,4))
Now you can access the i-th matrix (i-th z-slice of the "cube") via B[,,i], e.g.:
> B[,,2]
[,1] [,2] [,3]
[1,] 3 2 1
[2,] 2 4 2

R: subsetting N-dimensional arrays

Consider the following 3-dimensional array:
set.seed(123)
arr = array(sample(c(1:10)), dim=c(3,4,2))
which yields
> arr
, , 1
[,1] [,2] [,3] [,4]
[1,] 10 9 8 2
[2,] 5 1 4 10
[3,] 6 7 3 5
, , 2
[,1] [,2] [,3] [,4]
[1,] 6 7 3 5
[2,] 9 8 2 6
[3,] 1 4 10 9
I'd like to subset it like
arr[c(1,2), c(2,4), c(1)]
but the catch is that I don't know (a) which indices or (b) which dimension the indices are.
What is the best way to access an N-dimensional array with index variables?
ll = list(c(1,2), c(2,4), c(1))
arr[ll] # doesn't work
arr[grid.expand(ll)] # doesn't work
# ..what else?
use do.call, such as:
do.call(`[`, c(list(arr), ll))
or more cleanly, using a wrapper function:
getArr <- function(...)
`[`(arr, ...)
do.call(getArr, ll)
[,1] [,2]
[1,] 10 5
[2,] 7 3
There is the asub function from the abind package:
library(abind)
asub(arr, ll)
which can also do a lot more, in particular extract along a subset of the dimensions (https://stackoverflow.com/a/17752012/1201032). Worth having in your toolbox.

Resources