Matlab: how do I apply a function along one dimension of an array - arrays

I have an array of mxnx4 dimensions and a function with a 4-element vector input. I want to apply my function to give me an mxnx4 output, such that the function is applied mxn times (i.e. the 3rd dimension of my array becomes in the input of my function). Any ideas on how do do this would be massively appreciated. I have looked at arrayfun, but this seems not to address what I want to do. I also want to maintain the formatting of my function as it requires this formatting elsewhere in my code.
I.e.:
F=#(V)[V(1)+V(2);V(2)+V(3); V(3)+V(4); V(4)+V(1)]
to be applied to array M of dimensions 2x3x4 (m=2; n=3)
M = zeros(2,3,4);
M(:,:,1) = [1 2 3;4 5 6];
M(:,:,2) = [7 8 9;10 11 12];
M(:,:,3) = [13 14 15; 16 17 18];
M(:,:,4) = [19 20 21; 22 23 24];
to generate an array of dimensions 2x3x4
C(1,1,:) = F([1 7 13 19])
C(1,2,:) = F([2 8 14 20])
etc.
I can see a for loop would work, applying the following across the mxn matrix
C(m,n,:)=F(M(m,n,:))
However, I need to run this millions of times so would like a faster approach

Related

Matlab make new array of values without a loop

In Matlab, I don't know the best way to explain this except for an example. Let's say I have an array called tStart and a tDuration length:
tStart = [3,8,15,20,25];
tDuration = 2;
Is there some way to get a new array such that it would be:
[3,4,5,8,9,10,15,16,17,20,21,22,25,26,27]
So what I want is to use the initial tStart array then make up a new array with the starting value and then next corresponding values for the length of tDuration.
If I do [tStart(1:end)+tDuration] I get an array of ending values, but how can I get the start, end, and all the values in between?
If I [tStart(1:end):tStart(1:end)+tDuration] I get an error.
Any help of a way to do this without a loop would be greatly appreciated.
I would use MATLAB's implicit expansion, reshape, and the ordering of 2d arrays.
First, create a 2d array containing the desired values from tStart:
tStart = [3,8,15,20,25];
tDuration = 2;
tDurAdd = [0:tDuration].'; % numbers to add to tStart
tArray = tStart + tDurAdd;
This gives us
tArray =
3 8 15 20 25
4 9 16 21 26
5 10 17 22 27
These are the correct values, now we just have to reshape them to a row vector:
tResult = reshape(tArray, 1, []);
The final array is:
tResult =
3 4 5 8 9 10 15 16 17 20 21 22 25 26 27
Of course, this can all be done on one line:
tResult = reshape(tStart + [0:tDuration].', 1, []);

Mean values of a matrix in a matrix on Matlab

This is about matlab.
Let's say I have a matrix like this
A = [1,2,3,4,5;6,7,8,9,10;11,12,13,14,15]‍
Now I want to know how to get a mean value of a small matrix in A.
Like a mean of the matrix located upper left side [1,2;6,7]
The only way I could think of is cut out the part I want to get a value from like this
X = A(1:2,:);
XY = X(:,1:2);
and mean the values column wise Mcol = mean(XY);.
and finally get a mean of the part by meaning Mcol row-wise.
Mrow = mean(Mcol,2);
I don't think this is a smart way to do this so it would be great if someone helps me make it smarter and faster.
Your procedure is correct. Some small improvements are:
Get XY using indexing in a single step: XY = A(1:2, 1:2)
Replace the two calls to mean by a single one on the linearized submatrix: mean(XY(:)).
Avoid creating XY. In this case you can linearize using reshape as follows: mean(reshape(A(1:2, 1:2), 1, [])).
If you want to do this for all overlapping submatrices, im2col from the Image Processing Toolbox may be handy:
submatrix_size = [2 2];
A_sub = im2col(A, submatrix_size);
gives
A_sub =
1 6 2 7 3 8 4 9
6 11 7 12 8 13 9 14
2 7 3 8 4 9 5 10
7 12 8 13 9 14 10 15
that is, each column is one of the submatrices linearized. So now you only need mean(A_sub, 1) to get the means of all submatrices.

Partial sum of divisions of a vector

If there is a vector like this,
T = [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]
(the size of vector T can be flexible)
How can I get a array of 'sum of divisions'?
For example,
fn(T, 5) = [ (1+2+3+4+5) , (6+7+8+9+10), (11+12+13+14+15) , 16]
One option, which doesn't require the padding of zeros on the original array, is the use of accumarray and ceil:
div = 5;
out = accumarray(ceil((1:numel(T))/div).',T(:))
Another option using cumsum and diff instead:
div = 5;
T(ceil(numel(T)/div)*div) = 0;
cs = cumsum(T)
out = diff( [0 cs(div:div:end) ] )
Edit: once the padding is done, cumsum and diff are a little overkill and one should proceed as in Bentoy's answer.
Another way, close to the 2nd option of thewaywewalk:
div = 5;
T(ceil(numel(T)/div)*div) = 0;
out = sum(reshape(T,div,[])).'; % transpose if you really want a column vector
Also, one one-liner solution (I prefer this one):
out = blockproc(T,[1 5], #(blk) sum(blk.data), 'PadPartialBlocks',true);
Don't forget to set the parameter 'PadPartialBlocks', this is the key of avoiding explicit padding.
There is an in-built function vec2mat in Communications System Toolbox to convert a vector into a 2D matrix that cuts off after every N elements and puts into separate rows, padding the leftover places at the end with zeros to maintain 2D size . So, after using vec2mat, summing all the rows would be enough to give you the desired output. Here's the implementation -
sum(vec2mat(T,5),2)
Sample run -
>> T = 1:16;
>> vec2mat(T,5)
ans =
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 0 0 0 0
>> sum(vec2mat(T,5),2)
ans =
15
40
65
16

Trying to compare elements of on array with every element of another array in matlab

I'm using Matlab, and I'm trying to come up with a vectorized solution for comparing the elements of one array to every element of another array. Specifically I want to find the difference and see if this difference is below a certain threshold.
Ex: a = [1 5 10 15] and b=[12 13 14 15], threshold = 6
so the elements in a that would satisfy the threshold would be 10 and 15 since each value comes within 6 of any of the values in b while 1 and 5 do not. Currently I have a for loop going through the elements of a and subtracting an equivalently sized matrix from b (for 5 it would be a = [5 5 5 5]). This obviously takes a long time so I'm trying to find a vectorized solution. Additionally, the current format I have my data in is actually cells where each cell element has size [1 2], and I have been using the cellfun function to perform my subtraction. I'm not sure if this complicates the solution of each [1 2] block with the [1 2] block of the second cell. A vectorized solution response is fine, there is no need to do the threshold analysis. I just added it in for a little more background.
Thanks in advance,
Manwei Chan
Use bsxfun:
>> ind = any(abs(bsxfun(#minus,a(:).',b(:)))<threshold)
ind =
0 0 1 1
>> a(ind)
ans =
10 15

calculation of value from given matrix

suppose that we have following array :
a=[12 21 23 10 34 54 10 9 5 6 7 8]
a =
12 21 23 10 34 54 10 9 5 6 7 8
length(a)=
length(a)
ans =
12
now i want to create following vector b ,which b(1),b(2)...b(6) are following
b(1)=sqrt(a(1)^2+a(2)^2)
b(2)=sqrt(a(3)^2+a(4)^2)
b(3)=sqrt(a(5)^2+a(6)^2))
b(4)=sqrt(a(7)^2+a(8)^2)
b(5)=sqrt(a(9)^2+a(10)^2))
b(6)=sqrt(a(11)^2+a(12)^2)
i have wrote following code
or i=2:2:length(a)
b(i/2)=sqrt(a(i-1)^2+a(i)^2);
end
>> b
b =
24.1868 25.0799 63.8122 13.4536 7.8102 10.6301
but i am not sure if it is correct,pleas help me to clarify if everything is ok in my code
In matlab, loops are quite slow. Using vectors is much faster. I suggest therefore a solution without a loop:
a_1 = a(1:2:end);
a_2 = a(2:2:end);
b = sqrt(a_1.^2 + a_2.^2);
first, you create a vector a_1 containing all elements with odd indices of a and a vector a_2 containing all elements with even indices.
Then you square them element wise (.^) and take the square of the sum.
For you example of a, this is 75 times faster. As you increase the size of the array, you will save even more time.

Resources