R Multiplying each element of an array by a different number - arrays

I am trying to multiply each element of an array by an integer (along the first dimension). The tricky thing is that this integer will change for each element.
An example :
test <- array(dim = c(3,5,7))
test[1,,] <- 1
test[2,,] <- 10
test[3,,] <- 100
vec <- c(1,2,3)
The result I want is an array with the same dimension (3,5,7) and along the first dimension :
test[1,,] * vec[1]
test[2,,] * vec[2]
test[3,,] * vec[3]
This means
Result <- array(dim = c(3,5,7))
Result[1,,] <- 1
Result[1,,] <- 20
Result[1,,] <- 300
I think I am quite close with different functions like outer or apply but I think there is an easier way, as I have a lot of data to treat. For now, I found the outer function, and I should select something like the diagonal of the result.
Can someone help ?

slice.index might be helpful here
Result <- test * vec[slice.index(test, 1)]

How about
test*replicate(7, replicate(5, vec))

What's wrong with using apply like this?
sapply(1:length(vec), function(i) test[i,,]<<- test[i,,]*vec[i])

In this case you can just do
Result <- test*vec
Note that this will only work if the dimension that is being split and multiplied is the first one.

Related

Parallelize nested for-loop on 3 dimensional array in R

Using R on a Windows machine, I am currently running a nested loop on a 3D array (720x360x1368) which cycles through d1 and d2 to apply a function over d3 and assemble the output to a new array of similar dimensionality.
In the following reproducible example, I have reduced the dimensions by factor 10, to make execution faster.
library(SPEI)
old.array = array(abs(rnorm(50)), dim=c(72,36,136))
new.array = array(dim=c(72,36,136))
for (i in 1:72) {
for (j in 1:36) {
new.listoflists <- spi(ts(old.array[i,j,], freq=12, start=c(1901,1)), 1, na.rm = T)
new.array[i,j,] = new.listoflists$fitted
}
}
where spi() is a function from the SPEI package returning a list of lists, of which one particular list $fittedof length 1368 is used from each loop increment to cunstruct the new array.
While this loop works flawlessly, it takes quite a long time to compute. I have read that foreachcan be used to parallelize for loops.
However, I do not understand how the nesting and the assembling of the new array can be achieved such that the dimnames of the old and the new array are consistent.
(In the end, what I want to be able to, is to transform both the old and the new array into a "flat" long panel data frame using as.data.frame.table() and merge them along their three dimensions.)
Any help on how I can achieve the desired output using parallel computing will be highly appreciated!
Cheers
CubicTom
It would have been better with a reproducible example, here is what i come up with:
First create the cluster to use
cl <- makeCluster(6, type = "SOCK")
registerDoSNOW(cl)
Then you create the loop and close the cluster:
zz <- foreach(i = 1:720, .combine = c) %:%
foreach(j = 1:360, .combine = c ) %dopar% {
new.listoflists <- FUN(old.array[i,j,])
new.array[i,j,] <- new.listoflists$list
}
stopCluster(cl)
This will create a list zz containing every iteration of new.array[i,j,], then you can bind them together with:
new.obj <- plyr::ldply(zz, data.frame)
Hope this helps you!
I did not use as much of dimensions as your question because I wanted to ensure the behavior was correct.
So here I use mapply which take multiple arguments. The result is a list of the results. Then I wrapped it with matrix() to get the dimensions you hoped for.
Please note that i is repeated using times and j is repeated using each. This is critical as matrix() put entries by row first then wraps to the next column when the number of row is reached.
new.array = array(1:(5*10*4), dim=c(5,10,4))
# FUN: function which returns lists of
FUN <- function(x){
list(lapply(x, rep, times=3))
}
# result of the computation
result <- matrix(
mapply(
function(i,j,...){
FUN(new.array[i,j,])
}
,i = rep(1:nrow(new.array),times=ncol(new.array))
,j = rep(1:ncol(new.array),each=nrow(new.array))
,new.array=new.array
)
,nrow=nrow(new.array)
,ncol=ncol(new.array)
)

Create an array 1*3 containing only one 1 and rest 0

I am just learning matlab now. I faced a difficulty in creating an array of 3 elements in a row.
I wrote a code
Source = randi ([0,1],1,3);
which gave me output
[1,1,0].....
[0,1,1]....
but I was willing to get only one 1 and two zeros in the output instead of getting two 1 and one zero.
I know I am wrong because I am using randi function and gives random value of 0 & 1 and output I get can be [0,0,1] ... [1,0,0]... too.
My clear problem is to only get only one 1 if I repeat as many times. e.g. I should get only [0,0,1] or [0,1,0] or [1,0,0].
Hope I can get solution.
Thank you.
Ujwal
Here's a way using randperm:
n = 3; %// total number of elements
m = 1; %// number of ones
x = [ones(1,m) zeros(1,n-m)];
x = x(randperm(numel(x)));
Here is a couple of alternative solutions for your problem.
Create zero-filled matrix and set random element to one:
x = zeros(1, 3);
x(randi(3)) = 1;
Create 1x3 eye matrix and randomly circshift it:
x = circshift(eye(1,3), [0, randi(3)]);

Array - vector multiplication in R

I need a simple matrix-algebra or Kronicker product type operation to multiply an array and a vector in R to get to a specific result. Let's say I have the array:
ar<-array(c(rep(1,9),rep(10,9),rep(100,9)),dim=c(3,3,3))
And the vector c(1,2,3). Multiplying both by * multiplies each row on each slide of the array by 1,2, and 3 respectively. However, I need an operation to get to array
ar2<-array(c(rep(1,9),rep(20,9),rep(300,9)),dim=c(3,3,3))
instead. That is, is there a simple operation that would allow me to transform ar to ar2 using the vector I specified above? Thanks!
ar * rep(1:3, each=9) should work...
For an arbitrary sized array and an arbitrary set of multipliers, you know the dimensions of your array and the axis along which you want to perform your elementwise multiplication (in this case, the z axis):
each_arg <- prod(dim(ar)[1:2])
multipliers <- sample(1:10, 3)
ar2 <- ar * rep(multipliers, each=each_arg)
You can also look at the tensorA package

Matlab: Summation over Array Dimensions

I've done quite a bit of searching and haven't been able to find a satisfactory answer so far, so I'm sorry if this question has already been raised.
I'm stuck on how to sum over the dimensions of an array. I have array A(w0,lambda,2048,2048), and I would like to be able to define a second array U(w0, 2048, 2048) which is composed of the sum of A over dimension lambda.
So far I have been defining both A and U as follows:
A = zeros(length(w0),length(lambda),2048,2048);
U = zeros(length(w0),2048,2048);
for ii = 1:length(w0) % Scan through spot sizes
for aa = 1:length(lambda) % Scan through wavelengths
A(ii,aa,:,:) = ASM(w0(ii),lambda(aa),z1,z2);
end
U(ii,:,:) = sum(A,2);
end
Where ASM is just a function. z1 and z2 are defined earlier, and not relevant here.
I have been trying to come up with other possible ways of finding U(w0,2048,2048) as the sum over the second dimension of A (lambda), but haven't been successful...
Thanks for any pointers, and sorry again if this has already been resolved!
James.
From the sounds of it, you just want:
U = squeeze(sum(A, 2));
squeeze() eliminates singleton dimensions.
Here are two alternative solutions:
U = reshape(sum(A, 2), [length(w0) 2048 2048]);
or:
U = sum(A, 2);
U = U(:, 1, :, :);
Try using 'sum' function with a dimension argument, and collapse result on the desired dimensions.
z = rand(2,3,2,2);
q = sum(z,2); %sum all 3 matrices of size 2x2x2 to get 2x1x2x2 result
zz = q(:,1,:,:); %zz is now 2x2x2, by collapsing the dimension 2.

Invert an apply with rbind

Lets say that I have an array, foo, in R that has dimensions == c(150, 40, 30).
Now, if I:
bar <- apply(foo, 3, rbind)
dim(bar) is now c(6000, 30).
What is the most elegant and generic way to invert this procedure and go from bar to foo so that they are identical?
The trouble isn't getting the dimensions right, but getting the data back in the same order, within it's respected, original, dimension.
Thank you for taking the time, I look forward to your responses.
P.S. For those thinking that this is part of a larger problem, it is, and no, I cannot use plyr, quite yet.
I think you can just call array again and specify the original dimensions:
m <- array(1:210,dim = c(5,6,7))
m1 <- apply(m, 3, rbind)
m2 <- array(as.vector(m1),dim = c(5,6,7))
all.equal(m,m2)
[1] TRUE
I'm wondering about your initial transformation. You call rbind from apply, but that won't do anything - you could just as well have called identity!
foo <- array(seq(150*40*30), c(150, 40, 30))
bar <- apply(foo, 3, rbind)
bar2 <- apply(foo, 3, identity)
identical(bar, bar2) # TRUE
So, what is it you really wanted to accomplish? I was under the assumption that you had a couple (30) matrix slices and wanted to stack them and then unstack them again. If so, the code would be more involved than #joran suggested. You need some calls to aperm (as #Patrick Burns suggested):
# Make a sample 3 dimensional array (two 4x3 matrix slices):
m <- array(1:24, 4:2)
# Stack the matrix slices on top of each other
m2 <- matrix(aperm(m, c(1,3,2)), ncol=ncol(m))
# Reverse the process
m3 <- aperm(array(m2, c(nrow(m),dim(m)[[3]],ncol(m))), c(1,3,2))
identical(m3,m) # TRUE
In any case, aperm is really powerful (and somewhat confusing). Well worth learning...

Resources