Apply a replacement to each 3rd dimension of a 3D array - arrays

I have an mxnxp (3D) array A. I have a 2D matrix B with values ranging from 1:m in the first column and 1:n in the second column. What I'd like to do is NA out the indices that correspond to those given by B in each of the third dimension (heights?). So,
for (i in 1:p) {
A[,,i][B] = NA
}
Is there a way to do this without a for loop? I was thinking something like
A_NA = apply(A,3,function(x) x[B] = NA)
But that doesn't work.

We need to return the x and then assign it back to 'A'
A[] <- apply(A,3,function(x) { x[B] = NA; x})
Checking with the OP's solution
for (i in 1:p) {
A1[,,i][B] = NA
}
identical(A, A1)
#[1] TRUE
data
A <- array(1:40, c(5, 4, 2) )
B <- cbind(c(1, 2, 3, 4), c(2, 3, 1, 1))
p <- 2
A1 <- A

Related

Determing the length from a list in R

I have a list where each element is an array. Example data:
set.seed(24)
data <- list(individual1 = array(rnorm(3 * 3 * 2, 60),
dim = c(3, 3, 2), dimnames = list(NULL, NULL, c("rep1", "rep2"))),
individual2 = array(rnorm(3 * 3 * 2, 60), dim = c(3, 3, 2),
dimnames = list(NULL, NULL, c("rep1", "rep2")) ) )
I would like to find the length of the entire list. However, when I use length, I get 2, whereas I want 4 because there are 4 arrays. Is there another way to determine length for my question?
>length(data)
2
Like this?
sum(sapply(data, function(x) dim(x)[3]))
#[1] 4
Explanation: Your list in fact only contains 2 elements. The dimension of every list element is
lapply(data, dim)
#$individual1
#[1] 3 3 2
#
#$individual2
#[1] 3 3 2
In other words, every list elements has 2 3x3 arrays. We can therefore get the total number of 3x3 arrays in the list by summing the number of 3x3 arrays from every list element.

Vectorized matrix and array multiplication in R

I could not figure out, how to write a vectorized version of the following matrix and array multiplication:
v = rep(0.1, 2)
v2 = matrix(0, nrow = 2, ncol = 3)
A = matrix(0.25, nrow = 2, ncol = 3)
R = matrix(- 1, nrow = 2, ncol = 3)
P = array(1:12, dim = c(2, 2, 3))
for (i in 1:3) {
v2[, i] = A[, i] * (R[, i] + P[, , i] %*% v)
}
v = rowSums(v2)
Can someone help?
The problem that we are faced with is that we want to do matrix multiplication over P, a 3d array. As this is not efficiently possible, it is better to transform this array to a 2d column matrix.
P <- array(1:12, dim = c(2, 2, 3))
P <- matrix(P, nrow = 2)
The A and R matrices don't have to be adjusted for this to work
A <- matrix(0.25, nrow = 2, ncol = 3)
R <- matrix(-1, nrow = 2, ncol = 3)
Matrix multiplication with the v vector can then be accomplished by transforming the column vector into a sparse block diagonal matrix with the bdiag(...) function from the Matrix package.
library(Matrix)
v <- rep(0.1, 2)
v <- bdiag(v, v, v)
## [1,] 0.1 . .
## [2,] 0.1 . .
## [3,] . 0.1 .
## [4,] . 0.1 .
## [5,] . . 0.1
## [6,] . . 0.1
This gives the same result as before, however, this time in a vectorized manner.
v <- rowSums(A * (R + (P %*% v)))
## [1] 0.15 0.30
Edit: In the above equation I use two types of multiplication: *, the dot-product, which computes the element-wise products between two matrices of equal size, and %*%, the ordinary matrix product, which computes the matrix product of two conformable matrices, or in other words, the number of columns of the first, and the number of rows of the second matrix should be equal.
Edit2: As requested I have included how to transform the given P array to a matrix.
Edit3: This method can be generalized by introducing a variable n for the number of groups. The key adjustment is in the declaration of the block diagonal matrix, as next to individual matrices, this function also takes a list of matrices as input. This results in the following solution
library(Matrix)
n <- 3
P <- array(1:12, dim = c(2, 2, n))
P <- matrix(P, nrow = 2)
A <- matrix(0.25, nrow = 2, ncol = n)
R <- matrix(-1, nrow = 2, ncol = n)
v <- rep(0.1, 2)
v <- bdiag(rep(list(v),n))
v <- rowSums(A * (R + (P %*% v)))
## [1] 0.15 0.30

How to swap two row vectors inside a row vector?

i am trying to swap 2 row vectors which are inside a row vector.
For example:
a=[1 2 3];
b=[5 3];
c=[9 3 7 6];
d=[7 5];
X1= [ a, b , d, c ];
I want to do random swapping such that two of the a,b,c,d remains at the same position in X1 and the remaining two of them shuffles in X1. For example, some of the possible random swaps are:
[b,a,d,c] % a and b swap with each other whereas d and c remain at the same place
[d,b,a,c] % a and d swap with each other whereas b and c remain at the same place
[c,b,d,a] % a and c swap with each other whereas b and d remain at the same place
.....
.....
The proper and safe way to what you're trying to do is by assigning your variables to a cell, permuting the elements of the cell, and finally concatenating the result.
Imagine a specific permutation, say, [c, b, a, d]. This permutation can be coded as [3, 2, 1, 4] in terms of a mapping. The corresponding code to generate your array is then:
% generate input
a = [1, 2, 3];
b = [5, 3];
c = [9, 3, 7, 6];
d = [7, 5];
% generate cell to permute
tmpcell = {a, b, c, d};
% define our permutation
permnow = [3, 2, 1, 4];
% permute and concatenate the result into an array
result = [tmpcell{permnow}];
% check if this is indeed OK:
disp(isequal(result,[c, b, a, d])) % should print 1
The only thing you might still need is to generate a random configuration. This is easy: you just have to choose 2 random indices and swap them in [1, 2, 3, 4]. A lazy option to do this:
nvars = length(tmpcell); % generalizes to multiple variables this way
idperm = 1:nvars;
i1 = randi(nvars,1);
partperm = setdiff(idperm, i1); % vector of remaining indices, avoid duplication
i2 = partperm(randi(nvars-1,1)); % second index, guaranteed distinct from i1
permnow = idperm;
permnow([i1, i2]) = [i2, i1]; % swap the two indices

R: outer on array in first dimension

outer in R gives outer product of arrays. For example, for matrix A with dimension c(2, 3),
A <- matrix(1:6, 2, 3)
B <- outer(A, A, function(x,y) x + y)
B has dimension c(2, 3, 2, 3). But can I define a function myouter in a concise way to apply outer only in the first dimension, to get a matrix C?
C <- myouter(A, A, function(x,y) sum(x) + sum(y))
C can be obtained by the following tedious code.
C <- matrix(nrow = 2, ncol = 2)
for (i in 1:2) {
for (j in 1:2) {
C[i, j] <- sum(A[i, ])+ sum(A[j, ])
}
}

Array sorting using presorted ranking

I'm building a decision tree algorithm. The sorting is very expensive in this algorithm because for every split I need to sort each column. So at the beginning - even before tree construction I'm presorting variables - I'm creating a matrix so for each column in the matrix I save its ranking. Then when I want to sort the variable in some split I don't actually sort it but use the presorted ranking array. The problem is that I don't know how to do it in a space efficient manner.
A naive solution of this is below. This is only for 1 variabe (v) and 1 split (split_ind).
import numpy as np
v = np.array([60,70,50,10,20,0,90,80,30,40])
sortperm = v.argsort() #1 sortperm = array([5, 3, 4, 8, 9, 2, 0, 1, 7, 6])
rankperm = sortperm.argsort() #2 rankperm = array([6, 7, 5, 1, 2, 0, 9, 8, 3, 4])
split_ind = np.array([3,6,4,8,9]) # this is my split (random)
# split v and sortperm
v_split = v[split_ind] # v_split = array([10, 90, 20, 30, 40])
rankperm_split = rankperm[split_ind] # rankperm_split = array([1, 9, 2, 3, 4])
vsorted_dummy = np.ones(10)*-1 #3 allocate "empty" array[N]
vsorted_dummy[rankperm_split] = v_split
vsorted = vsorted_dummy[vsorted_dummy!=-1] # vsorted = array([ 10., 20., 30., 40., 90.])
Basically I have 2 questions:
Is double sorting necessary to create ranking array? (#1 and #2)
In the line #3 I'm allocating array[N]. This is very inefficent in terms of space because even if split size n << N I have to allocate whole array. The problem here is how to calculate rankperm_split. In the example original rankperm_split = [1,9,2,3,4] while it should be really [1,5,2,3,4]. This problem can be reformulated so that I want to create a "dense" integer array that has maximum gap of 1 and it keeps the ranking of the array intact.
UPDATE
I think that second point is the key here. This problem can be redefined as
A[N] - array of size N
B[N] - array of size N
I want to transform array A to array B so that:
Ranking of the elements stays the same (for each pair i,j if A[i] < A[j] then B[i] < B[j]
Array B has only elements from 1 to N where each element is unique.
A few examples of this transformation:
[3,4,5] => [1,2,3]
[30,40,50] => [1,2,3]
[30,50,40] => [1,3,2]
[3,4,50] => [1,2,3]
A naive implementation (with sorting) can be defined like this (in Python)
def remap(a):
a_ = sorted(a)
b = [a_.index(e)+1 for e in a]
return b

Resources