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);
Related
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)
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
I have two vectors
A = [...] %size 1x320
B = [...] %size 1x192
I would like to combine the two vectors in one but the way I want to combine them is the following:
Take the first 5 elements of vector A then add 3 elements from vector B add the next 5 elements from vector A then add the next element from vector B and so on until the both vectors are combined in one. I think the process should be repeated 64 times since 320/5=64 and 192/3=64.
Is there any built-in Matlab function to do that?
I don't think that there is a built-in function that does exactly that, but the following will do what you want:
A=randi(10,1,320);
B=randi(10,1,192);
C=zeros(1,length(A)+length(B));
for i=1:5
C(i:8:end)=A(i:5:end);
end
for i=6:8
C(i:8:end)=B(i-5:3:end);
end
Then the array C is the combined array.
Edit: Another way to do that, without for loops:
A=randi(10,1,320);
B=randi(10,1,192);
A_new=reshape(A,5,[]);
B_new=reshape(B,3,[]);
C=[A_new;B_new];
C=reshape(C,[1,numel(C)]);
In this solution, by specifying the third parameter in reshape(A,5,[]) to be [], we allow it to adjust the number of columns according to the length of A, given that the number of rows in the reshaped array is 5. In addition, numel(C) is the total number of elements in the array C. So this solution can be easily generalized to higher number of arrays as well.
I have a string array:
size(entries)
ans =
1 19413
I would like to rearrange the array to 4853 rows and 4 columns:
output=permute(entries,[4853 4]);
but get following error:
Error using permute ORDER contains an invalid permutation index.
What is the (probably obvious thing) I am doing wrong? thanks
You currently have 19413 elements, yet you wish to reshape this into a 4853 x 4 matrix that consists of 4853 * 4 = 19412 elements. No function in the world will help you do this because the original and target amount of elements don't match - they're off by one element. If you remove one of the elements...say... the last one, then we're getting somewhere.
Supposing you made a mistake and included that extra element by accident, you don't use permute here, but you use reshape. The second argument to reshape is the amount of elements to spread out for each target dimension, and that's what you're looking for. First remove the extraneous element that appears at the end of the array, then reshape the matrix:
output = reshape(entries(1:end-1),[4853 4]);
I'm 3 years late, but here's to anyone still looking for an answer.
In your case as mentioned above, yes you should use reshape() while minding that you preserve the total number of elements.
You use permute() when you want to reorder the dimensionality of an n-dimensional (ND) matrix.
The ORDER parameter specifies the order of the columns.
For example, if matrix A is LxMxN, the following line would make it MxLxN.
A = permute(A,[2 1 3]);
Hope this clears things.
I am not 100% what the role of the 1: is here. At which index to start the copy? But then why not two such parameters for the rank 2 array?
To be a little more explicit:
In Fortran90 and up you access a single array value by giving a single index, and access a subarray (a window of the array) by giving a range of indices separated by a colon.
a(1) = 0.
a(2:5) = (/3.14,2.71,1.62,0./)
You can also give a step size.
a(1:5:2) = (/0,2.71,0./)
And finally, you can leave out values and a default will be inserted. So if a runs from index 1 to 5 then I could write the above as
a(::2) = (/0,2.71,0./)
and the 1 and 5 are implied. Obviously, you shouldn't leave these out if it makes the code unclear.
With a multidimensional array, you can mix and match these on each dimension, as in your example.
You're taking a slice of array2, namely the elements in the D'th column from row 1 to C and putting them in the slice of array1 which is elements 1 through A
So both slices are 1-dimensional arrays
Slice may not be the correct term in Fortran