R Accessing vector inside list inside Array - arrays

I have a very long Array (1955x2417x1) in R where each position stores a list of two vector (named "max" and "min") of length 5.
I would like to find a simple way to create a multidimensional array (dim 1955x2417x5) where each position holds a single value from vector "max"
I have looked at answers such as array of lists in r
but so far without success.
I know I can access the list in each position of the array using
myarray[posX, PosY][[1]][["max"]]
but how to apply that to the whole Array?
SO far I have tried
newArray <- array( unlist(myarray[][[1]][["max"]]), c(1955, 2417, 5))
and
NewArray <-parApply(cl, myarray, c(1:2), function(x) {
a=x[[1]][["max"]]
} )
but the results are not right.
Do you have any suggestion?

Let
e <- list(min = 1:3, max = 4:6)
arr <- array(list(e)[rep(1, 8)], c(2, 4))
dim(arr)
# [1] 2 4
Then one option is
res <- apply(arr, 1:2, function(x) x[[1]][["max"]])
dim(res)
# [1] 3 2 4
and, if the order of dimensions matters,
dim(aperm(res, c(2, 3, 1)))
# [1] 3 2 4

Related

Correct way of maintaining array structure in R [duplicate]

I am working with 3D arrays. A function takes a 2D array slice (matrix) from the user and visualizes it, using row and column names (the corresponding dimnames of the array). It works fine if the array dimensions are > 1.
However, if I have 1x1x1 array, I cannot extract the slice as a matrix:
a <- array(1, c(1,1,1), list(A="a", B="b", C="c"))
a[1,,]
[1] 1
It is a scalar with no dimnames, hence part of the necessary information is missing. If I add drop=FALSE, I don't get a matrix but retain the original array:
a[1,,,drop=FALSE]
, , C = c
B
A b
a 1
The dimnames are here but it is still 3-dimensional. Is there an easy way to get a matrix slice from 1x1x1 array that would look like the above, just without the third dimension:
B
A b
a 1
I suspect the issue is that when indexing an array, we cannot distinguish between 'take 1 value' and 'take all values' in case where 'all' is just a singleton...
The drop parameter of [ is all-or-nothing, but the abind package has an adrop function which will let you choose which dimension you want to drop:
abind::adrop(a, drop = 3)
## B
## A b
## a 1
Without any extra packages, the best I could do was to apply and return the sub-array:
apply(a, 1:2, identity)
# or
apply(a, 1:2, I)
# B
#A b
# a 1

how to extract 1x1 array slice as matrix in R?

I am working with 3D arrays. A function takes a 2D array slice (matrix) from the user and visualizes it, using row and column names (the corresponding dimnames of the array). It works fine if the array dimensions are > 1.
However, if I have 1x1x1 array, I cannot extract the slice as a matrix:
a <- array(1, c(1,1,1), list(A="a", B="b", C="c"))
a[1,,]
[1] 1
It is a scalar with no dimnames, hence part of the necessary information is missing. If I add drop=FALSE, I don't get a matrix but retain the original array:
a[1,,,drop=FALSE]
, , C = c
B
A b
a 1
The dimnames are here but it is still 3-dimensional. Is there an easy way to get a matrix slice from 1x1x1 array that would look like the above, just without the third dimension:
B
A b
a 1
I suspect the issue is that when indexing an array, we cannot distinguish between 'take 1 value' and 'take all values' in case where 'all' is just a singleton...
The drop parameter of [ is all-or-nothing, but the abind package has an adrop function which will let you choose which dimension you want to drop:
abind::adrop(a, drop = 3)
## B
## A b
## a 1
Without any extra packages, the best I could do was to apply and return the sub-array:
apply(a, 1:2, identity)
# or
apply(a, 1:2, I)
# B
#A b
# a 1

R Array subsetting: flexible use of drop

As it has been noticed in Subsetting R array: dimension lost when its length is 1
R drops every dimension when subsetting and its length is 1.
The drop property helps avoid that.
I need a more flexible way to subset :
> arr = array(1, dim= c(1,2,3,4))
> dim(arr[,,1,])
[1] 2 4
> dim(arr[,,1,,drop=F])
[1] 1 2 1 4
I want a way to subset by dropping the 3rd dimension (actually the dimension where I put the subset 1) and keepping the 1st dimension (the dimensions where no subset is put).
It should return an array with dimension = 1 2 4
My issue is that I started coding with an array with no dimension = 1, but when coming to deal with some cases where a dimension is 1, it crashes. The function I need provides a way to deal with the array as if the dimension is not 1.
Two ways to do this, either use adrop from package abind, or build a new array with the dimensions you choose, after doing the subsetting.
library(abind)
arr <- array(sample(100, 24), dim=c(1, 2, 3, 4))
arr2 <- adrop(arr[ , , 1, , drop=FALSE], drop=3)
dim(arr2)
arr3 <- array(arr[ , , 1 , ], dim=c(1,2,4))
identical(arr2, arr3)
If you want a function that takes a single specified margin, and a single index of that margin, and drops that margin to create a new array with exactly one fewer margin, here is how to do it with abind:
specialsubset <- function(ARR, whichMargin, whichIndex) {
library(abind)
stopifnot(length(whichIndex) == 1, length(whichMargin) == 1, is.numeric(whichMargin))
return(adrop(x = asub(ARR, idx = whichIndex, dims = whichMargin, drop = FALSE), drop = whichMargin))
}
arr4 <- specialsubset(arr, whichMargin=3, whichIndex=1)
identical(arr4, arr2)

How to create sub-arrays access the i-th dimension of an array within for()?

In a for-loop, I run in i over an array which I would like to sub-index in dimension i. How can this be done? So a minimal example would be
(A <- array(1:24, dim = 2:4))
A[2,,] # i=1
A[,1,] # i=2
A[,,3] # i=3
where I index 'by foot'. I tried something along the lines of this but wasn't successful. Of course one could could create "2,," as a string and then eval & parse the code, but that's ugly. Also, inside the for loop (over i), I could use aperm() to permute the array such that the new first dimension is the former ith, so that I can simply access the first component. But that's kind of ugly too and requires to permute the array back. Any ideas how to do it more R-like/elegantly?
The actual problem is for a multi-dimensional table() object, but I think the idea will remain the same.
Update
I accepted Rick's answer. I just present it with a for loop and simplified it further:
subindex <- c(2,1,3) # in the ith dimension, we would like to subindex by subindex[i]
for(i in seq_along(dim(A))) {
args <- list(1:2, 1:3, 1:4)
args[i] <- subindex[i]
print(do.call("[", c(list(A), args)))
}
#Build a multidimensional array
A <- array(1:24, dim = 2:4)
# Select a sub-array
indexNumber = 2
indexSelection = 1
# Build a parameter list indexing all the elements of A
parameters <- list(A, 1:2, 1:3, 1:4)
# Modify the appropriate list element to a single value
parameters[1 + indexNumber] <- indexSelection
# select the desired subarray
do.call("[", parameters)
# Now for something completely different!
#Build a multidimensional array
A <- array(1:24, dim = 2:4)
# Select a sub-array
indexNumber = 2
indexSelection = 1
reduced <- A[slice.index(A, indexNumber) == indexSelection]
dim(reduced) <- dim(A)[-indexNumber]
# Also works on the left-side
A[slice.index(A, 2)==2] <- -1:-8

retain array class when operation results in 2-dimensional matrix

I have an array that can have one or more pages or sheets (my names for the third dimension). I am attempting to perform operations on the array. When there is only one sheet or page the result of the operation is a matrix. I would like the result to be an array. Is there a way to retain the class array even when the result of the operation has only 1 sheet or page?
Here is an example. I would like my.var.2 and my.var.3 to be arrays. The variable my.pages is set to 1 here, which seems to be causing the problem. However, my.pages can be >1. If my.pages <- 2 then my.var.2 and my.var.3 are arrays.
set.seed(1234)
my.rows <- 10
my.columns <- 4
my.pages <- 1
my.var.1 <- array( rnorm((my.rows*my.columns*my.pages), 10, 2),
c(my.rows,my.columns,my.pages))
my.var.1
my.var.2 <- 2 * my.var.1[,-my.columns,]
my.var.3 <- 10 * my.var.1[,-1,]
class(my.var.2)
class(my.var.3)
my.var.2 <- as.array(my.var.2)
my.var.3 <- as.array(my.var.3)
class(my.var.2)
class(my.var.3)
my.var.2 <- as.array( 2 * my.var.1[,-my.columns,])
my.var.3 <- as.array(10 * my.var.1[,-1,] )
class(my.var.2)
class(my.var.3)
The switch to matrix causes problems when I try to use my.var.1 and my.var.2 in nested for-loops.
The following if statement seems to solve the problem, but also seems a little clunky. Is there a more elegant solution?
if(my.pages == 1) {my.var.2 <- array(my.var.2, c(my.rows,(my.columns-1),my.pages))}
From help([):
Usage:
x[i, j, ... , drop = TRUE]
...
drop: For matrices and arrays. If 'TRUE' the result is coerced to
the lowest possible dimension (see the examples). This only
works for extracting elements, not for the replacement. See
'drop' for further details.
Your code, revisited:
set.seed(1234)
my.rows <- 10
my.columns <- 4
my.pages <- 1
my.var.1 <- array( rnorm((my.rows*my.columns*my.pages), 10, 2),
c(my.rows,my.columns,my.pages))
my.var.2 <- 2 * my.var.1[,-my.columns,,drop=FALSE]
my.var.3 <- 10 * my.var.1[,-1,,drop=FALSE]
class(my.var.2)
## [1] "array"
class(my.var.3)
## [1] "array"

Resources