Splitting a vector up in to smaller vectors based on variance?

1 view (last 30 days)
Hi, I have a large number of microscopy image stacks that show the effect of different flow rates on a particle. I have used matlab to give me the angle of the particle at different times during the experiment, but its output is one vector of angles.
I would like to split this vector up, so that I can measure the standard deviation of the angles when no flow is applied, X flow is applied, no flow, Y flow, etc...
My main problem seems to be appending values onto a cell. Here, I'm trying to say that when the average of Angle(k) and it's three following angles is greater than 25, then Angle(k) does into Out{1}, if not it goes into a new cell Out{2}, and so on. Does anyone have any suggestion on how to do this?
for k=1:numFrames-4
if abs(Angle(k))+abs(Angle(k+1))+abs(Angle(k+2))+abs((Angle(k+3))/4 > 25;
Out{Indy} = ????;
else Indys = Indy+1;
Out{Indys}=????;
end
end

Accepted Answer

Stephen23
Stephen23 on 26 Sep 2014
Edited: Stephen23 on 26 Sep 2014
Solution Two (based on feedback from Alan).
Assuming that numFrames and Angle are arrays, and all values are known before this code is run, then all means can be calculated at once ( vectorization! ):
N = 4;
A = reshape(randperm(110),[],10)-50;
B = conv2(abs(A),ones(1,N),'valid')/N;
Out_first = A(B>25);
Out_second = A(...);
Out_third = A(...);
This uses some fake angle data A, from -49 to 60. The mean is calculated using a convolution, and then compared and the values allocated to output vectors. You can easily change the number of angles that are meaned N. All you need to do is pick the indexing for the outputs (e.g. B>25 ).
Note this uses a handy feature of MATLAB indexing, where the index can be smaller than the array it is indexing into.
  3 Comments
Alan
Alan on 26 Sep 2014
You're right actually, this works best.
Thanks Stephen!
Stephen23
Stephen23 on 26 Sep 2014
Glad to help.
You should keep in mind Guillaume's comments that although this solution splits your data up as per your question, it may not be the best solution to split your data up. It might be tidier/faster/bug-free-er/... if you simply keep the data together, and keep track of the indices for subsetting the data for applying with later calculations.

Sign in to comment.

More Answers (2)

Stephen23
Stephen23 on 26 Sep 2014
Edited: Stephen23 on 26 Sep 2014
Using vectorization would make this code simpler and easier to understand.
For example you can perform abs on all of the Angle values simultaneously (if it is an array):
abs(Angle(k))+abs(Angle(k+1))+abs(Angle(k+2))+abs((Angle(k+3))/4 > 25;
can simply be performed all in one go:
mean(abs(Angle(k:k+3)))>25
(Assuming that your misplaced bracket really was intended to calculated the mean of all four values.)
This allows us to simplify the code:
if mean(abs(Angle(k:k+3)))>25
...
else
...
end
But in your case you might be able to use the indexing directly to allocate the values, without an if statement:
idx = mean(abs(Angle(k:k+3)))>25;
Out{2-idx} = Angle(k);
If you wish to accumulate more values on the same array within the cells, then you can append values:
Out = {[],[]};
for k=1:numFrames-4
idx = mean(abs(Angle(k:k+3)))>25;
Out{2-idx}(end+1) = Angle(k);
end
but it really would be better to preallocate the arrays in Out and then insert the values. Probably the best way to do this would be to use conv to calculate all of the means in one go, compare these values to 25, and then allocate to the output arrays using the comparison as indexing.
  2 Comments
Alan
Alan on 26 Sep 2014
Hi, thanks for your response. This code splits the original vector into two: one with all the values above the threshold, and one with all the values below it. However what I'd like to be able to do move along the vector 'Angle', binning the first few hundred values which are above the threshold into one vector, then the next few hundred (when flow is first applied) into a second vector, then a third with no flow, etc... So we should end up with multiple vectors of all the flow rates. Do you think this is possible?
Stephen23
Stephen23 on 26 Sep 2014
Edited: Stephen23 on 26 Sep 2014
Is this possible: yes, have a look at my other solution, which may be more what you are looking for.

Sign in to comment.


Guillaume
Guillaume on 26 Sep 2014
Edited: Guillaume on 26 Sep 2014
If all you want to do is measure the standard deviation according to your bins, I wouldn't bother splitting the array, and would just use accumarray:
angles = rand(1, 2000); %some values for demos
splitpoints = [200 450 750]; %some values for demos, indicates start of next bin.
splitlength = diff([1 splitpoints numel(angles)+1]);
bins = cell2mat(arrayfun(@(sp, idx) zeros(1, sp) + idx, splitlength, 1:numel(splitlength), 'UniformOutput', false));
binstd = accumarray(bins', angles, [], @std);
Otherwise, you can use mat2cell to split up your array any way you want and do whatever processing you want:
angles = rand(1, 2000); %some values for demos
splitpoints = [200 450 750]; %some values for demos, indicates start of next bin.
splitlength = diff([1 splitpoints numel(angles)+1]);
splitangles = mat2cell(angles, 1, splitlength);
binstd = cellfun(@std, splitangles);
edited for typos

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!