In a 4D array, I would like to find the unique minimum value across the 4th dimension. I want to get a matrix of the array indices for the minimum.
I have tried solving the issue with the following code block. I would have liked using which.min, but I haven't found a good way to return the array indices.
dims =c(3,3,3,4)
# create sample data with multiple mins in [,,,1]
mat_rep = array(c(rep(0,3),sample(1:prod(dims))), dim = dims)
pos_rep = apply(mat_rep, 4, function(x) which(x == min(x), arr.ind = T)) # get position of unique minimum
# create sample data with unique min
mat_norep = array(sample(1:prod(dims)), dim = dims)
pos_norep = apply(mat_norep, 4, function(x) which(x == min(x), arr.ind = T))
# formating depending on class of pos_ object
format_pos = function(x, dims){
if(class(x) == "matrix") x = t(x)
if(class(x) == "list") x = do.call(rbind, lapply(x, head, 1))
x = cbind(x, 1:dims[4]) # add 4th dimension
return(x)
}
format_pos(pos_norep, dims = dims)
format_pos(pos_rep, dims = dims)
The described solution works, however it doesn't work generally and the if(class()) and cbind(x, 1:dims[4]) in my opinion is prone to producing errors.
Does someone have a cleaner way of solving this issue?
To create uniform outputs you can call arrayInd explicitly on the output of apply(..., which.min), instead of implicitly as in which(..., arr.ind = TRUE). The fourth dimension indices still need to be added manually though:
## add 4D indices using 1D values
start.ind <- (seq_len(dims[4]) - 1) * prod(head(dims, 3))
arrayInd(apply(mat_rep, 4, which.min) + start.ind, .dim = dims)
#> [,1] [,2] [,3] [,4]
#> [1,] 1 1 1 1
#> [2,] 1 3 3 2
#> [3,] 1 3 2 3
#> [4,] 3 1 1 4
arrayInd(apply(mat_norep, 4, which.min) + start.ind, .dim = dims)
#> [,1] [,2] [,3] [,4]
#> [1,] 2 1 3 1
#> [2,] 1 2 1 2
#> [3,] 1 2 1 3
#> [4,] 2 2 3 4
## add 4D indices using cbind
cbind(arrayInd(apply(mat_rep, 4, which.min), .dim = head(dims, 3)), seq_len(dims[4]))
#> [,1] [,2] [,3] [,4]
#> [1,] 1 1 1 1
#> [2,] 1 3 3 2
#> [3,] 1 3 2 3
#> [4,] 3 1 1 4
cbind(arrayInd(apply(mat_norep, 4, which.min), .dim = head(dims, 3)), seq_len(dims[4]))
#> [,1] [,2] [,3] [,4]
#> [1,] 2 1 3 1
#> [2,] 1 2 1 2
#> [3,] 1 2 1 3
#> [4,] 2 2 3 4
Data
dims <- c(3,3,3,4)
mat_rep <- array(c(rep(0,3),sample(1:prod(dims))), dim = dims)
mat_norep <- array(sample(1:prod(dims)), dim = dims)
Related
Suppose you have an n-dimensional, homogeneous data structure (array) in R with a variable but fixed number of dimensions:
n_dim <- 3
n_row <- 3
a <- array(seq(n_row ^ n_dim), dim = rep(n_row, n_dim))
a
>, , 1
>
> [,1] [,2] [,3]
>[1,] 1 4 7
>[2,] 2 5 8
>[3,] 3 6 9
>[..]
Is there a simple syntax to access a subscript of a given dimension, instead of counting the commas from n_dim or counting the position with 1-dim positions a[c(1,...)]? Is there any a[get row in dim] method that provides this already?
# Give me the 1st row of the "last" dimension
expr <- paste0("a[",
paste0(rep(", ", n_dim - 1), collapse = ""),
x,
"]")
expr
> [1] "a[, , 1]"
eval(parse(text = expr))
> [,1] [,2] [,3]
>[1,] 1 4 7
>[2,] 2 5 8
>[3,] 3 6 9
Thank you!
One option would be abind
library(abind)
asub(a, 1, n_dim)
# [,1] [,2] [,3]
#[1,] 1 4 7
#[2,] 2 5 8
#[3,] 3 6 9
I´m coding in R and I have a 3 dimensional array that contains data (ab in the example). Then I have a matrix that contains indices of the 3rd array dimension (idx). This matrix has the same number of rows and columns of the array. I want to use the indices contained in idx to extract data from the array, to get a matrix with same dimension of idx. Please see the example below:
a <- c(1:9)
b <- rev(a)
#array of data
ab <- array(c(a,b), dim = c(3,3,2))
ab
, , 1
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
, , 2
[,1] [,2] [,3]
[1,] 9 6 3
[2,] 8 5 2
[3,] 7 4 1
#matrix of indices
idx <- matrix(sample(1:2,9,replace=TRUE), nrow = 3)
idx
[,1] [,2] [,3]
[1,] 2 2 2
[2,] 2 1 1
[3,] 1 1 1
#now I want to get the following matrix:
[,1] [,2] [,3]
[1,] 9 6 3
[2,] 8 5 8
[3,] 3 6 9
#these two don´t do the job
ab[idx]
ab[ , ,idx]
Does anybody know how can I get that?
Many thanks!
Sara
We need an index for row/column and the third dimension (from 'idx') to extract the elements. We do this by cbinding the row index, column index with the 'idx'.
i1 <- dim(ab)[1]
j1 <- dim(ab)[2]
matrix(ab[cbind(rep(seq_len(i1), j1),rep(seq_len(j1), each = i1), c(idx))], ncol=3)
# [,1] [,2] [,3]
#[1,] 9 6 3
#[2,] 8 5 8
#[3,] 3 6 9
Might be a bit complicated, but it works at least:
First of all my idx:
[,1] [,2] [,3]
[1,] 2 2 1
[2,] 1 2 1
[3,] 2 2 2
First I made it both to a vector:
idVec <- as.vector(idx)
d3mat <- apply(ab,3,as.vector)
Then I constructed a vector, to run over each element:
len <- length(idVec)
len <- 1:len
Then I apllied a function to each element of the vector len:
resultvec <- sapply(len, function(x, vec, mat){return(mat[x,vec[x]])}, mat=d3mat, vec=idVec)
And then transform the result back to a matrix:
matrix(resultVec,3,3)
[,1] [,2] [,3]
[1,] 9 6 7
[2,] 2 5 8
[3,] 7 4 1
If I have the array
> (arr = array(c(1,1,2,2), c(2,2,2)))
, , 1
[,1] [,2]
[1,] 1 2
[2,] 1 2
, , 2
[,1] [,2]
[1,] 1 2
[2,] 1 2
then how could I apply a column vector, say c(3,3), to each row of each matrix and sum these up? So essentially, I need to do 4 * c(1,2) %*% c(3,3). Could an apply function be used here?
Thanks everyone for the help! I believe the correct method is
sum(apply(arr, c(1,3), function(x) x %*% c(1,2,3)))
which here we are dotting the vector [1,2,3] to each row of each matrix in our array called arr and summing them up. Note that here I changed the array to be
arr = array(c(1,2,3,4,5,6,7,8,9,10,11,12), c(2,3,2))
arr
, , 1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
, , 2
[,1] [,2] [,3]
[1,] 7 9 11
[2,] 8 10 12
and now the vector we are dotting the rows with is c(1,2,3) instead of c(3,3) in the original post.
EDITED
This should give you the answer:
l <- list(matrix(c(1,1,2,2), ncol = 2),
matrix(c(1,1,2,2), ncol = 2))
l
#[[1]]
# [,1] [,2]
# [1,] 1 2
# [2,] 1 2
#
# [[2]]
# [,1] [,2]
# [1,] 1 2
# [2,] 1 2
ivector <- c(3, 3) # a vector that is multiplied with the rows of each listelement
# apply over all listelements
res <- lapply(l, function(x, ivector){
#apply to all rows of the matrizes
apply(x, 1, function(rowel, ivector){
return(sum(rowel %*% ivector))
}, ivector = ivector)
}, ivector = ivector)
res
#[[1]]
#[1] 9 9
#
#[[2]]
#[1] 9 9
# And finally sum up the results:
sum(Reduce("+", res))
#[1] 36
Does that help?
I believe that a similar question was asked here, but I can't seem to find it anymore.
I have two matrices with different dimensions, and I want to equalise them so that I can combine them in an array.
for example, I have the following two matrices:
a <- matrix(1:6, 3, 2)
b <- matrix(1:12, 4, 3)
a
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
b
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
Because I am working with time series data, I would like the added rows/colums to have NAs in them. In my example, matrix a would get an extra column and an extra row only containing NAs like this:
[,1] [,2] [,3]
[1,] 1 4 NA
[2,] 2 5 NA
[3,] 3 6 NA
[4,] NA NA NA
In my dataset I will have 79 matrices with unequal dimensions, and I need to make them as big as the matrix with the largest dimensions.
If b is the largest matrix, you can create a matrix with the same dimensions as b, filled with NA, and replace the rows and columns corresponding to the smaller matrix a with the values of a:
a2 <- "[<-"(x = matrix(NA, nrow = nrow(b), ncol = ncol(b)),
i = 1:nrow(a), j = 1:ncol(a),
value = a)
a2
# [,1] [,2] [,3]
# [1,] 1 4 NA
# [2,] 2 5 NA
# [3,] 3 6 NA
# [4,] NA NA NA
Example with several matrices, where we find the largest matrix and pad all matrices with NA to match the dimension of the largest.
# create some matrices of different size
a <- matrix(1:6, nrow = 3, ncol = 2)
b <- matrix(1:12, nrow = 4, ncol = 3)
c <- matrix(1:4, nrow = 2, ncol = 2)
# put them in a list
l <- list(a, b, c)
# index of largest (here, max number of rows) matrix in the list
id <- which.max(unlist((lapply(l, nrow))))
# pad matrices with NA
l2 <- lapply(l, function(x){
x <- "[<-"(x = matrix(NA, nrow = nrow(l[[id]]), ncol = ncol(l[[id]])),
i = 1:nrow(x), j = 1:ncol(x),
value = x)
})
l2
# [[1]]
# [,1] [,2] [,3]
# [1,] 1 4 NA
# [2,] 2 5 NA
# [3,] 3 6 NA
# [4,] NA NA NA
#
# [[2]]
# [,1] [,2] [,3]
# [1,] 1 5 9
# [2,] 2 6 10
# [3,] 3 7 11
# [4,] 4 8 12
#
# [[3]]
# [,1] [,2] [,3]
# [1,] 1 3 NA
# [2,] 2 4 NA
# [3,] NA NA NA
# [4,] NA NA NA
As you only want to extend the small matrix with NA, we can use a simple approach such as:
create a matrix as big as b, with only NA. Code:
extended.a = matrix(NA,nrow(b),ncol(b))
fill this matrix with the values from a. Code:
extended.a[cbind(rep(1:nrow(a),ncol(a)), rep(1:ncol(a),each=nrow(a)))] = a
edit:
As per Roland's suggestion, you can also get the vector of indices with which(..., arr.ind=TRUE).
For example, which(TRUE | a, arr.ind=TRUE)
Or even: which(matrix(TRUE,nrow(a),ncol(a), arr.ind=TRUE)
Or far better, using the expand.grid function: expand.grid(1:nrow(a), 1:ncol(a))
Maybe we can try the following base R option
> replace(NA + b, cbind(c(row(a)), c(col(a))), a)
[,1] [,2] [,3]
[1,] 1 4 NA
[2,] 2 5 NA
[3,] 3 6 NA
[4,] NA NA NA
Here, I need to build a jagged arrays to store data, here is the code for you
a<-list()
b=1
for(i in 1:5){
b+1
a[i]<-array(0,c(b,1))
}
You can see, what I want to do it to save arrays of different dimensions, even though here is 0 as an example, into a.
Would you please help me on how to create a jagged arrays/lists/matrices, to store different dimensions arrays?
Thanks
For create jagged arrays also know as ragged arrays this is an example using list function and using x[1] for indexing:
x = list(a=c(1,2,3,4),b=c(-1,-3,-4),c=c(23,45,23,45,25,48),d=c(2,1))
stk = stack(x)
ustk= unstack(stk)
identical(ustk,x)
[1] TRUE
> x
$a
[1] 1 2 3 4
$b
[1] -1 -3 -4
$c
[1] 23 45 23 45 24 48
$d
[1] 2 1
> x[1]
$a
[1] 1 2 3 4
> x[2]
$b
[1] -1 -3 -4
other method:
# empty list to start with
X <- list()
# we get a vector
v1 <- c(1, 2, 3, 4, 5)
# add it to the ragged array
X <- c(X, list(v1))
# get another couple of vectors and add them as well
v2 <- c(9, 8, 7, 6)
v3 <- c(2, 4, 6, 8)
X <- c(X, list(v2, v3))
# add some more elements to the first vector in
# the vector directly
X[[1]] <- c(X[[1]], 4, 3, 2, 1)
For created jagged matrices this is an example:
x = c(3,2,5)
struct = lapply(x, function(i){
sapply(1:i, function(k){
c(rep(NA, k-1),exp( - (0:(i-k))))
})
})
> x
[1] 3 2 5
> struct
[[1]]
[,1] [,2] [,3]
[1,] 1.0000000 NA NA
[2,] 0.3678794 1.0000000 NA
[3,] 0.1353353 0.3678794 1
[[2]]
[,1] [,2]
[1,] 1.0000000 NA
[2,] 0.3678794 1
[[3]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1.00000000 NA NA NA NA
[2,] 0.36787944 1.00000000 NA NA NA
[3,] 0.13533528 0.36787944 1.0000000 NA NA
[4,] 0.04978707 0.13533528 0.3678794 1.0000000 NA
[5,] 0.01831564 0.04978707 0.1353353 0.3678794 1