R : How to fill an array with this peculiar calculation? - arrays

I would fill an array D with a loop, and only with a loop (please), where my data are structured in this particular way:
A <- data.frame(matrix(nrow=12,ncol=10))
c_2 <- c(0.003,0.004)
an <- sapply(c_2,function(x) x*c(1:12))
B <-array(an,c(12,1,2))
set.seed(1)
C<- rnorm(10,0.6,0.1)
D <- array(NA,c(12,1,20))
f_12 <- exp(c(0:11)/12)
for (k in 1:length(A)){
for (i in 1:dim(B)[3]){
for (z in 1:length(C)){
M_nat <- C[z]
A[,z] <- f_12*M_nat
ris_1 <- A[,k]
cost_1 <- B[,,i]
prov_1 <- cost_1*ris_1
D[,,k*i] <- prov_1
}
}
}
My expected result is an array D, where each [,,z] dimension is a result from B[,,1] and B[,,2] for each column of A(A in the loop).
With the above code the R result is an array where the first ten z dimension are full, and after, some have values, and others are NA. Where did I go wrong?

outer(1:10, 1:2, "*") tells you which indices you can fill with D[,,k*i]:
# [,1] [,2]
# [1,] 1 2
# [2,] 2 4
# [3,] 3 6
# [4,] 4 8
# [5,] 5 10
# [6,] 6 12
# [7,] 7 14
# [8,] 8 16
# [9,] 9 18
#[10,] 10 20
These are the ones not possible:
(1:20)[!(1:20 %in% outer(1:10, 1:2, "*"))]
#[1] 11 13 15 17 19
And indeed, those elements are not filled in D. Note that you filled some elements more than once.
You could use (i-1) * 10 + k instead if k*i.

Related

Using a list-matrix to supply indices to N-dimensional object

I am working on a partial differential equations project where some N-dimensional objects are required. I got stuck in padding one N-dim object with a copy of each of its dimensions. Here is the function:
padreplicate <- function(a, padSize) {
# Pad an array by replicating values.
numDims <- length(padSize)
idx <- vector("list", numDims)
for (k in 1:numDims) {
M <- dim(a)[k] # 32
onesVector <- ones(1, padSize[k])
idx[[k]] <- c(onesVector, 1:M, M * onesVector)
}
# return(a[ unlist(idx[1]), unlist(idx[2]) ]) # this works for 2D
# return(a[ idx[[1]], idx[[2]] ]) # this also works for 2D
# return(a[apply(idx, 1, function(x) unlist[x])]) #:( doesn't work
# a[sapply(apply(idx, 1:length(dim(idx)), function(x) eval(parse(text=x))), unlist)] #:(
# 2D: "a[idx[[1]], idx[[2]]]" 3D: "a[idx[[1]], idx[[2]]], idx[[3]]]"
dim_text = paste0("a", "[ ",
paste0(sapply(1:length(idx), function(x)
paste0("idx", "[[", x, "]]")), collapse = ", ")," ]")
eval(parse(text=dim_text)) # this works
}
The first argument is the N-dim object; it could be a matrix, a 3D array or higher dimensional array.
An example for a 2D object or matrix would be:
# pad a matrix 4x3 with c(1,1)
set.seed(123456)
mx = matrix(sample.int(9, size = 9*100, replace = TRUE), nrow = 4, ncol = 3)
mx
# [,1] [,2] [,3]
# [1,] 8 4 9
# [2,] 7 2 2
# [3,] 4 5 8
# [4,] 4 1 6
padreplicate(mx, c(1,1))
The padded matrix looks like this:
[,1] [,2] [,3] [,4] [,5]
[1,] 8 8 4 9 9
[2,] 8 8 4 9 9
[3,] 7 7 2 2 2
[4,] 4 4 5 8 8
[5,] 4 4 1 6 6
[6,] 4 4 1 6 6
For a 3-D array the input array and the padded array.
ar = array(sample.int(9, size = 9*100, replace = TRUE), dim = c(3, 3, 1))
ar
padreplicate(ar, c(1,1,1))
# input 3x3x1 array
, , 1
[,1] [,2] [,3]
[1,] 3 4 6
[2,] 7 2 9
[3,] 3 4 8
# padded 5x5x3 array
, , 1
[,1] [,2] [,3] [,4] [,5]
[1,] 3 3 4 6 6
[2,] 3 3 4 6 6
[3,] 7 7 2 9 9
[4,] 3 3 4 8 8
[5,] 3 3 4 8 8
, , 2
[,1] [,2] [,3] [,4] [,5]
[1,] 3 3 4 6 6
[2,] 3 3 4 6 6
[3,] 7 7 2 9 9
[4,] 3 3 4 8 8
[5,] 3 3 4 8 8
, , 3
[,1] [,2] [,3] [,4] [,5]
[1,] 3 3 4 6 6
[2,] 3 3 4 6 6
[3,] 7 7 2 9 9
[4,] 3 3 4 8 8
[5,] 3 3 4 8 8
These are all correct results.
My question is this: "is there a better way of doing this N-dim padding operation?
EDIT 1
Thanks to Frank, now the N-dimensional padreplicate function:
padreplicate <- function(a, padSize) {
# Pad an array by replicating values.
numDims <- length(padSize)
idx <- vector("list", numDims)
for (k in 1:numDims) {
M <- dim(a)[k] # 32
onesVector <- ones(1, padSize[k])
idx[[k]] <- c(onesVector, 1:M, M * onesVector)
}
do.call( `[`, c(list(a), idx))
}
EDIT 2
Using matrix instead of my function ones. Sorry about that.
padreplicate <- function(a, padSize) {
# Pad an array by replicating values.
numDims <- length(padSize)
idx <- vector("list", numDims)
for (k in 1:numDims) {
M <- dim(a)[k] # 32
onesVector <- matrix(1, 1, padSize[k])
idx[[k]] <- c(onesVector, 1:M, M * onesVector)
}
do.call( `[`, c(list(a), idx))
}

3D array filled by row in R sorted first from left to right, after descendant

I need to create a 3D array sorted by row, from left to right and descendent.
x <- 100
I have tried with this:
b <- array(1:96, dim= c(8,4,3))
but it sorts firstly descendently. Using apperm(b) doesn't work as well
The result I want is this:
, , 1
1 2 3 4 5
6 7 8 9 10
11 12 13 14
15 16 17 18
19 20 21 22
array by default fill values along 1st dimension, then 2nd dimension, then 3rd; What you are looking for is fill it in the order of (2nd, 1st, 3rd), you can initialize the array with the shape of 1st dimension and 2nd dimension switched and then use aperm on it:
b <- aperm(array(1:96, dim= c(4,8,3)), c(2,1,3))
# ^ ^ ^ ^ switch the dimension twice here
b
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12
Edit: My first try, but #Psidom's answer is the right way to do this.
You need to make it as a combination of 3 matrices and then combine them into an array. In the code below I used 96*i/3 to make it flexible for more than 3 matrices to be combined.
b <- array( c( aperm(array(1:(96*1/3), dim = c(4,8))),
aperm(array(33:(96*2/3), dim = c(4,8))),
aperm(array(65:(96*3/3), dim = c(4,8))) ) ,
dim = c(8, 4, 3))
This will be the output:
b[, , 1]
# [,1] [,2] [,3] [,4]
# [1,] 1 2 3 4
# [2,] 5 6 7 8
# [3,] 9 10 11 12
# [4,] 13 14 15 16
# [5,] 17 18 19 20
# [6,] 21 22 23 24
# [7,] 25 26 27 28
# [8,] 29 30 31 32

Return the indices of a 3D array in R based on multiple values

I would like to obtain the indices of a 3D array in R (ie. arr[x,y,z]) based on multiple values. Specifically, using the first z dimension to subset values in the second z dimension. Here is a example:
# create example array
> m1 <- matrix(c(rep("a",5), rep("b",5), rep("c",5)), nr = 5)
> m2 <- matrix(c(rep(100, 5), rep(10, 5), rep(10, 5)), nr = 5)
> arr <- array(c(m1, m2), dim = c(dim(m1), 2))
#use which() to return the indices in m2 that correspond to indices with
#"a" and "c" values in m1. This does not work as expected.
> ac.ind <- which(arr[,,1] %in% c("a", "c"), arr.ind = T)
> ac.ind
[1] 1 2 3 4 5 11 12 13 14 15
which() returns an vector of positions in m1 that correspond to "a" and "c", not the matrix indices (the (x,y) positions). I would like ac.ind to return:
row col
[1,] 1 1
[2,] 2 1
[3,] 3 1
[4,] 4 1
[5,] 5 1
[1,] 1 3
[2,] 2 3
[3,] 3 3
[4,] 4 3
[5,] 5 3
If I do a more simple which() subset, it does return the indices:
#use which to return indices in m2 that correspond to only "a" in m1
>a.ind <- which(arr[,,1] == c("a"), arr.ind = T)
>a.ind
row col
[1,] 1 1
[2,] 2 1
[3,] 3 1
[4,] 4 1
[5,] 5 1
I am using %in% since I want to subset based on two values in m1 ("a" and "c" values). Is there a way to return the indices of an array based on two values in R?
The issue is that arr[,,1] %in% c("a", "c") returns a vector. One way is to cast this as a matrix with the number of rows equaling the first dimension of arr:
ac.ind <- which(matrix(arr[,,1] %in% c("a", "c"), nrow=dim(arr)[1]), arr.ind = T)
## row col
## [1,] 1 1
## [2,] 2 1
## [3,] 3 1
## [4,] 4 1
## [5,] 5 1
## [6,] 1 3
## [7,] 2 3
## [8,] 3 3
## [9,] 4 3
##[10,] 5 3
Something like this but it is not very efficient because it has to go twice through the data:
ac.ind <- which(arr[,,1] == "c" | arr[,,1] == "a" , arr.ind = T)
ac.ind
row col
[1,] 1 1
[2,] 2 1
[3,] 3 1
[4,] 4 1
[5,] 5 1
[6,] 1 3
[7,] 2 3
[8,] 3 3
[9,] 4 3
[10,] 5 3

array in R number of items to replace is not a multiple of replacement length

I would like to ask, how to set a value in array using looping. say like this
a<-3
b<-4
for( i in 1:5)
{
x[i] <- cbind(a*i, b*i)
}
but i always get error saying : In x[i] <- cbind(a * i, b * i) :
number of items to replace is not a multiple of replacement length. I used "paste" but seems it's not the solution. What is the problem ? If it were solved, can I get the value by using ; for example x[2][,2] to get the value of b * 2 ?
thank you
You can do it this way :
a <- 3
b <- 4
i <- 1:5
x <- cbind(a*i, b*i)
Make use of the matrix functions and the fact that R computes directly on vectors and matrices.
In your case, try this:
outer(1:5, 3:4, FUN = "*")
[,1] [,2]
[1,] 3 4
[2,] 6 8
[3,] 9 12
[4,] 12 16
[5,] 15 20

How to find a row or column under specific conditions in a matrix in R [duplicate]

This question already has answers here:
given value of matrix, getting it's coordinate
(2 answers)
Closed 7 years ago.
For example, if we have a matrix or say array with the following format
How can we find the index of rows or columns which only have numbers between 10 to 20 inside ?
M = array(c(1,1,12,34,0,19,15,1,0,17,12,0,21,1,11,1), dim=c(4,4))
And, also, I am not allowed to use for or while loops to do this.
Another thing is that the matrix or array may have a more than 2 dimensions. if the method can also apply to multi-dimensional matrix or array, it will be better for me. Thanks.
Instead of trying to find the index of qualified single elements, I need to find those rows or columns in which all the elements are between the interval.
In this example, I hope to have a result telling me that Row number 3 is a row that all the numbers within this row are between 10 to 20.
Use which(..., arr.ind = TRUE). Here I assume between means 10 and 20 are non-inclusive
which(M > 10 & M < 20, arr.ind = TRUE)
# row col
# [1,] 3 1
# [2,] 2 2
# [3,] 3 2
# [4,] 2 3
# [5,] 3 3
# [6,] 3 4
This will also work on 3-dimensional arrays (and higher).
## Three dimensions
dim(M) <- c(2, 4, 2)
which(M > 10 & M < 20, arr.ind = TRUE)
# dim1 dim2 dim3
# [1,] 1 2 1
# [2,] 2 3 1
# [3,] 1 4 1
# [4,] 2 1 2
# [5,] 1 2 2
# [6,] 1 4 2
## Four dimensions
dim(M) <- rep(2, 4)
which(M > 10 & M < 20, arr.ind = TRUE)
# dim1 dim2 dim3 dim4
# [1,] 1 2 1 1
# [2,] 2 1 2 1
# [3,] 1 2 2 1
# [4,] 2 1 1 2
# [5,] 1 2 1 2
# [6,] 1 2 2 2
## ... and so on
Note: To include 10 and 20, just use M >= 10 & M <= 20
Data:
M <- structure(c(1, 1, 12, 34, 0, 19, 15, 1, 0, 17, 12, 0, 21, 1,
11, 1), .Dim = c(4L, 4L))
Update: From your edit, you can find the row numbers for which all values are between 10 and 20 with
which(rowSums(M >= 10 & M <= 20) == ncol(M))
# [1] 3

Resources