How to find the nearest value of a number by comparing two nested cell arrays?

I have a cell array idp{1x58} which contains the indices of local maxima of each time series. I have another cell array qq{1x58} that contains indices of local minima for every time series.
I want to compare every elemt in the array idp with qq and I want to find the closest values above and below the element in idp.
For ex: idp{1,3} = 411.
Comparing it with qq{1,3}, 376 and 497 are the closest values above and below 411.
How do I do this operation?

 Risposta accettata

pairs is a cell array the same size as idp and qq. Each element is a 1x2 vector of the values in qq that are just below and above the values in idp.
% Inputs
idp = {381 402 411 359};
qq ={[168 262 498 637],[288,564,669],[88 257 376 497 535],[55 159 217 377 525 681]};
% closest values [below, above] idp
pairs = cellfun(@(a,b)[max(b(b<a)),min(b(b>a))],idp,qq,'UniformOutput',false);
If you'd rather return an nx2 matrix,
pairs = cell2mat(pairs');

6 Commenti

Works like a charm..Thank you so much!
Glad I could help!
One thing to keep in mind is that if there is no value in qq that is less than or greater than the corresponding value in idp, the pairs output will only return 1 value.
Example:
% Inputs
idp = {381};
qq ={[168 199 262]};
% closest values [below, above] idp
pairs = cellfun(@(a,b)[max(b(b<a)),min(b(b>a))],idp,qq,'UniformOutput',false);
% = {[262]}
You may want to add a comment to your code the explains this in case that ever causes problems. One way around that would be to wrap all of the qq values with -inf and inf so there will always be a value greater or less than idp. That would look like this:
qq = cellfun(@(x)[-inf,x,inf],qq,'UniformOutput',false);
Then the example above would return {262 , Inf}
This is exactly the problem that I am facing now. Thank you for bringing it up.
qq is generated by the following code:
for i = 1:length(files)
[~,PM{i}]=islocalmin(TFWS{i,:});
loc{i}=PM{:,i}>0.9;
qq{i}=find(loc{:,i});
end
Here TFWS is a nested cell array of time series. PM contains the prominence factors for each local minima point. loc contains the local minima whose prominence factor is greater than 0.9. qq returns the index values of these prominent local minima.
After using the code you gave, I realized that certain elements in [pairs] had only one value because cetain time series did not have more than 1 local minima with a prominence factor greater than 0.9.
My question is:
1)Is there a way to get the indices of the cells in [pairs] which have only one element
2)Once I have the indices, can I go back to qq generation code (shown above) and change the prominence limit to 0.1 instead of 0.9 just for those indices and then recalculate [pairs] and then add it back to the original [pairs]?
"1)Is there a way to get the indices of the cells in [pairs] which have only one element"
Sure, that's easy using cellfun.
If you didn't implement the [-inf,inf] suggestion, this will return a logical array identifying elements of pairs that only have 1 value.
idx = cellfun(@(x)numel(x)<2,pairs);
If you did implement the [-inf,inf] suggestion,
idx = cellfun(@(x)any(isinf(x)),pairs);
"2)Once I have the indices, ... "
You could do it that way but it doesn't sound streamlined. Do you have the idp values prior to the loop that calculates qq? If so, you could to a small test right there in that loop. It would look like this
for i = 1:length(files)
[~,PM{i}]=islocalmin(TFWS{i,:});
loc{i}=PM{:,i}>0.9;
qq{i}=find(loc{:,i});
% Test if there is a min and max in qq for the corresponding idp
if ~Your_Test_Here % FALSE means the test failed and you have to change prominence
loc{i}=PM{:,i} > 0.1;
qq{i}=find(loc{:,i});
end
end
Thanks a lot. Based on your suggestions, I wrote the following code and it worked.
for i = 1:length(files)
[~,PM{i}]=islocalmin(TFWS{i,:});
loc{i}=PM{:,i}>0.9;
qq{i}=find(loc{:,i});
pairs = cellfun(@(a,b)[max(b(b<a)),min(b(b>a))],idp,qq,'UniformOutput',false);
if length(pairs{1,i})==1
loc{i}=PM{:,i}>0.1;
qq{i}=find(loc{:,i});
pairs = cellfun(@(a,b)[max(b(b<a)),min(b(b>a))],idp,qq,'UniformOutput',false);
end
end
Good work!
I just though of a small improvement you could make but it's not necessary. In your current version, there are two lines that call cellfun() and those lines are identical. A small problem with this approach is that if you ever make changes to one line, you need to make the same changes to the other line and that's often overlooked (imagine you make a change a year from now and forget that you must do the same for the other line).
To avoid that problem, you could wrap the cellfun() line into an anonymous function so that it's only defined once. The first line below has been added and the two celfun() lines have been replaced. Also, I added {i} to (idp{i},qq{i}) -- I think that's what you meant to do.
pairsFunc = @(a,b)cellfun(@(a,b)[max(b(b<a)),min(b(b>a))],a,b,'UniformOutput',false);
for i = 1:length(files)
[~,PM{i}]=islocalmin(TFWS{i,:});
loc{i}=PM{:,i}>0.9;
qq{i}=find(loc{:,i});
pairs = pairsFunc(idp{i},qq{i});
if length(pairs{1,i})==1
loc{i}=PM{:,i}>0.1;
qq{i}=find(loc{:,i});
pairs = pairsFunc(idp{i},qq{i});
end
end
Also note that you're overwriting the pairs variable on each iteration instead of storing the values. Is that really what you want to do?

Accedi per commentare.

Più risposte (0)

Categorie

Community Treasure Hunt

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

Start Hunting!

Translated by