How to average over the fourth dimension of a 4-D array in R - arrays

I have a 4-D array in R and I want to average my array over the fourth dimension so that it gets reduced to a 3-D array. Is there a simple command to do this or is it faster to just do it inside of a for loop?
For example, imagine I have the following 4-D array A and I want some code that would produce the answer in A.mean
A = array(2,c(3,4,2,2))
A[,,,2] = 3
A.mean = array(2.5,c(3,4,2))

We can use
apply(A, c(1,2,3), FUN=mean)

Related

N-dimensional array indexing in Matlab : find array in middle

I am working with N-dimensional array and have a problem with the array indexing. I have a task to find an (N-1)-dimensional array in the middle N-dimensional array.
Let me explain in detail with 3D array. A is a 3-dimensional array that has split into groups. In each group, there are b - number of 2-dimensional arrays in the group. I have simulated it as:
b=5;
A=rand(2,2,20);
groups = reshape(A, size(A,1), size(A,2),b, []);
groups is 4-dimensional array, the 4-th dimension is a number of groups ( here it 4).
To find a middle in each group I have added the following loop:
for ii=1:size(groups,4) % Loop over all groups/slices
middle(:,:,ii) = groups(:,:,(w-1)/2+1,ii); % 1 2 3 4 5 : the middle is 3
end
middle is 3-dimensional array that collects middle array in each group.
As you see in my example I have used b=5( odd number). My problem is with even number b.
I have tried to implement it as ( rewrite the loop above);
l=rem(w,2);
for ii=1:size(groups,4) % Loop over all groups/slices
if l==1
middle(:,:,ii) = groups(:,:,(w-1)/2+1,ii);
else
middle(:,:,ii) = groups(:,:,(w-1)/2,ii);
end
end
But it doesn't work. Matlab gives me an error in the line l=rem(w,2);
Could you suggest to me how I can fix it? Is there another way to implement it?
You should use floor of ceil to round the index to whichever element you want:
middle_index = floor((w-1)/2+1);
Here, the middle of 4 is 2, using ceil you’d pick index 3.
Next, you can extract the arrays in a single indexing operation:
middle = groups(:,:,middle_index,:);
Finally, use squeeze or reshape to get rid of the 3rd index:
middle = squeeze(middle);

Sub2ind with three dimension - access all of dimension

Say A is a 3x4x5 array. I am given a vector a, say of dimension 2 and b of dimension 2. If I do A(a,b,:) it will give 5 matrices of dimensions 2x2. I instead want the piecewise vectors (without writing a for loop).
So, I want the two vectors of A which are given by (a's first element and b's first element) and (a's second element and b's second element)
How do I do this without a for loop? If A were two dimensions I could do this using sub2ind. I don't know how to access the entire vectors.
You can use sub2ind to find the linear index to the first element of each output vector: ind = sub2ind(size(A),a,b). To get the whole vectors, you can't do A(ind,:), because the : has to be the 3rd dimension. However, what you can do is reshape A to be 2D, collapsing the first two dimensions into one. We have a linear index to the vectors we want, that will correctly index the first dimension of this reshaped A:
% input:
A = rand(3,4,5);
a = [2,3];
b = [1,2];
% expected:
B = [squeeze(A(a(1),b(1),:)).';squeeze(A(a(2),b(2),:)).']
% solution:
ind = sub2ind(size(A),a,b);
C = reshape(A,[],size(A,3));
C = C(ind,:)
assert(isequal(B,C))
You can change a and b to be 3d arrays just like A and then the sub2ind should be able to index the whole matrix. Like this:
Edit: Someone pointed out a bug. I have changed it so that a correction gets added. The problem was that ind1, which should have had the index number for each desired element of A was only indexing the first "plane" of A. The fix is that for each additional "plane" in the z direction, the total number of elements in A in the previous "planes" must be added to the index.
A=rand(3,4,5);
a=[2,3];
b=[1,2];
a=repmat(a,1,1,size(A,3));
b=repmat(b,1,1,size(A,3));
ind1=sub2ind(size(A),a,b);
correction=(size(A,1)*size(A,2))*(0:size(A,3)-1);
correction=permute(correction,[3 1 2]);
ind1=ind1+repmat(correction,1,2,1);
out=A(ind1)

How to get the mean of first values in arrays in matrix in Matlab

If I have a square matrix of arrays such as:
[1,2], [2,3]
[5,9], [1,4]
And I want to get the mean of the first values in the arrays of each row such:
1.5
3
Is this possible in Matlab?
I've used the mean(matrix, 2) command to do this with a matrix of single values, but I'm not sure how to extend this to deal with the arrays.
Get the first elements in all arrays of matrix, then call mean function
mean(matrix(:,:,1))
maybe you need to reshape before call mean
a = matrix(:,:,1);
mean(a(:))
You can apply mean function inside mean function to get the total mean value of the 2D array at index 1. You can do similary with array at index 2. Consider the following snapshot.
After staring at your problem for a long time, it looks like your input is a 3D matrix where each row of your formatting corresponds to a 2D matrix slice. Therefore, in proper MATLAB syntax, your matrix is actually:
M = cat(3, [1,2; 2,3], [5,9; 1,4]);
We thus get:
>> M = cat(3, [1,2; 2,3], [5,9; 1,4])
M(:,:,1) =
1 2
2 3
M(:,:,2) =
5 9
1 4
The first slice is the matrix [1,2; 2,3] and the second slice is [5,9; 1,4]. From what it looks like, you would like the mean of only the first column of every slice and return this as a single vector of values. Therefore, use the mean function and index into the first column for all rows and slices. This will unfortunately become a singleton 3D array so you'll need to squeeze out the singleton dimensions.
Without further ado:
O = squeeze(mean(M(:,1,:)))
We thus get:
>> O = squeeze(mean(M(:,1,:)))
O =
1.5000
3.0000

MATLAB pairwise differences in Nth dimension

Say i have a N-Dimensional matrix A that can be of any size. For example:
A = rand([2,5,3]);
I want to calculate all possible pairwise differences between elements of the matrix, along a given dimension. For example, if i wanted to calculate the differences along dimension 3, a shortcut would be to create a matrix like so:
B = cat(3, A(:,:,2) - A(:,:,1), A(:,:,3) - A(:,:,1), A(:,:,3) - A(:,:,2));
However, i want this to be able to operate along any dimension, with a matrix of any size. So, ideally, i'd like to either create a function that takes in a matrix A and calculates all pairwise differences along dimension DIM, or find a builtin MATLAB function that does the same thing.
The diff function seems like it could be useful, but it only calculates differences between adjacent elements, not all possible differences.
Doing my research on this issue, i have found a couple of posts about getting all possible differences, but most of these are for items in a vector (and ignore the dimensionality issue). Does anyone know of a quick fix?
Specific Dimension Cases
If you don't care about a general solution, for a dim=3 case, it would be as simple as couple lines of code -
dim = 3
idx = fliplr(nchoosek(1:size(A,dim),2))
B = A(:,:,idx(:,1)) - A(:,:,idx(:,2))
You can move around those idx(..) to specific dimension positions, if you happen to know the dimension before-hand. So, let's say dim = 4, then just do -
B = A(:,:,:,idx(:,1)) - A(:,:,:,idx(:,2))
Or let's say dim = 3, but A is a 4D array, then do -
B = A(:,:,idx(:,1),:) - A(:,:,idx(:,2),:)
Generic Case
For a Nth dim case, it seems you need to welcome a party of reshapes and permutes -
function out = pairwise_diff(A,dim)
%// New permuting dimensions
new_permute = [dim setdiff(1:ndims(A),dim)];
%// Permuted A and its 2D reshaped version
A_perm = permute(A,new_permute);
A_perm_2d = reshape(A_perm,size(A,dim),[]);
%// Get pairiwse indices for that dimension
N = size(A,dim);
[Y,X] = find(bsxfun(#gt,[1:N]',[1:N])); %//' OR fliplr(nchoosek(1:size(A,dim),2))
%// Get size of new permuted array that would have the length of
%// first dimension equal to number of such pairwise combinations
sz_A_perm = size(A_perm);
sz_A_perm(1) = numel(Y);
%// Get the paiwise differences; reshape to a multidimensiona array of same
%// number of dimensions as the input array
diff_mat = reshape(A_perm_2d(Y,:) - A_perm_2d(X,:),sz_A_perm);
%// Permute back to original dimension sequence as the final output
[~,return_permute] = sort(new_permute);
out = permute(diff_mat,return_permute);
return
So much for a generalization , huh!

How to permute the arrays within a cell array without using loops

I have a two arrays within a <1x2 cell>. I want to permute those arrays. Of course, I could use a loop to permute each one, but is there any way to do that task at once, without using loops?
Example:
>> whos('M')
Name Size Bytes Class Attributes
M 1x2 9624 cell
>> permute(M,p_matrix)
This does not permute the contents of the two arrays within M.
I could use something like:
>> for k=1:size(M,2), M{k} = permute(M{k},p_matrix); end
but I'd prefer not to use loops.
Thanks.
This seems to work -
num_cells = numel(M) %// Number of cells in input cell array
size_cell = size(M{1}) %// Get sizes
%// Get size of the numeric array that will hold all of the data from the
%// input cell array with the second dimension representing the index of
%// each cell from the input cell array
size_num_arr = [size_cell(1) num_cells size_cell(2:end)]
%// Dimensions array for permuting with the numeric array holding all data
perm_dim = [1 3:numel(size_cell)+1 2]
%// Store data from input M into a vertically concatenated numeric array
num_array = vertcat(M{:})
%// Reshape and permute the numeric array such that the index to be used
%// for indexing data from different cells ends up as the final dimension
num_array = permute(reshape(num_array,size_num_arr),perm_dim)
num_array = permute(num_array,[p_matrix numel(size_cell)+1])
%// Save the numeric array as a cell array with each block from
%// thus obtained numeric array from its first to the second last dimension
%// forming each cell
size_num_arr2 = size(num_array)
size_num_arr2c = num2cell(size_num_arr2(1:end-1))
M = squeeze(mat2cell(num_array,size_num_arr2c{:},ones(1,num_cells)))
Some quick tests show that mat2cell would prove to be the bottleneck, so if you don't mind indexing into the intermediate numeric array variable num_array and use it's last dimension for an equivalent indexing into M, then this approach could be useful.
Now, another approach if you would like to preserve the cell format would be with arrayfun, assuming each cell of M to be a 4D numeric array -
M = arrayfun(#(x) num_array(:,:,:,:,x),1:N,'Uniform',0)
This seems to perform much better than with mat2cell in terms of performance.
Please note that arrayfun isn't a vectorized solution as most certainly it uses loops behind-the-scenes and seems like mat2cell is using for loops inside its source code, so please do keep all these issues in mind.

Resources