danjoro
danjoro

Reputation: 111

How to count number of maximum peak in range Matlab

Let say I have value A = [20 35 50 57 78 90 105 120 143], B=[2 40; 45 80; 85 145]; A is position of maximum peak value and B is range. How to identify a number of maximum peak values in every range?

The answer I want is [2 3 4]

Additionally I'd like a cellarray peak containing the corresponding peak values:

peak = 
      3 x 1 cell:
      [20 35]
      [50 57 78]
      [90 105 120 143]

Upvotes: 1

Views: 142

Answers (3)

Adriaan
Adriaan

Reputation: 18176

A = [20 35 50 57 78 90 105 120 143];
B = [2 40; 45 80; 85 145];
C = zeros(size(B,1),1); % Initialise C
pks = cell(size(B,1),1); % Initalise peak value collector
for ii = 1:size(B,1)
   pks{ii,1} = A(find(A>B(ii,1) && A<B(ii,2)));
   C(ii,1) = numel(pks{ii,1});
end
C =

     2     3     4

Explanation: The for loop crawls through B via its rows. For each row it uses the value in column one as a lower threshold and the value in column 2 as a higher threshold. The values in array A are checked against this and collected in the cell array pks. Finally numel returns just the number of elements found this way and stores that in C.

I assumed you are defining your ranges as open intervals, i.e. the boundaries do not belong to the set. If on the other hand you want closed intervals, simple use this:

C(ii) = numel(find(A>=B(ii,1) & A<=B(ii,2)));

A slightly faster method using logicals instead of find, thanks to @rayryeng:

C = zeros(size(B,1),1); % Initialise C
for ii = 1:size(B,1)
   tmp = A > B(ii,1) & A < B(ii,2);
   pks{ii,1} = A(tmp);
   C(ii,1) = sum(tmp);
end

This works approximately the same as above, albeit faster. The logicals A > B(ii,1) & A < B(ii,2) place a 1 on every location within the interval and a 0 on all other locations. Just sum the ones and you've got your desired number. This can be used as logical indexing to get the values of A. Open and closed intervals work the same as above.

Upvotes: 4

Divakar
Divakar

Reputation: 221524

Here's one using bsxfun, max and nanmax -

%// Mask of valid binning for A within the bins defined by the columns of B
mask = bsxfun(@ge,A(:),B(:,1).') & bsxfun(@le,A(:),B(:,2).')

%// Create interval version of A
A_intv = bsxfun(@times,mask,A(:))
A_intv(~mask) = nan

%// Get argmax for each bin
[~,max_mask_idx] = nanmax(A_intv,[],1)

%// Get start+1 indices for each bin
[~,start_idx] = max(mask,[],1)

%// Finally the output after subtracting start indices from max_mask_idx
out = max_mask_idx - (start_idx-1)

Upvotes: 3

rayryeng
rayryeng

Reputation: 104474

An alternative method is to use bsxfun and permute. What we can do is make this into a 3D problem where each slice tells you how many elements are in between each of the corresponding ranges in B. You'd them sum up over every column of each slice:

%// Given
A = [20 35 50 57 78 90 105 120 143];
B = [2 40; 45 80; 85 145];

%// Create the 3D matrix we talked about
BL = permute(B(:,1), [2 3 1])
BR = permute(B(:,2), [2 3 1])
out = bsxfun(@ge, A, BL) & bsxfun(@le, A, BR);

%// Reshape output into a vector
vals = reshape(sum(out, 2), 1, []);

We get:

>> vals

vals =

     2     3     4

Upvotes: 3

Related Questions