How to use arrayfun with built-in Matlab functions where the variable parameter is passed with 'Name', 'Value'?

3 views (last 30 days)
I want to speed up a for loop where I call the function findpeaks, hence I thought of using arrayfun.
What I want to change in each loop iteration is the value of the 'MinPeakHeight' argument in findpeaks.
x=[ 6.9100 6.1800 6.0500 5.7900 5.5000 5.2400 4.9800 4.6800 4.5100 4.6191 5.2582 5.9801 6.9525 13.2387 13.5548 12.1637 10.3495 9.2243...
9.0334 6.3900 6.3300 6.0500 6.1700 6.1100 6.0800 5.0500 5.4400 6.2600 6.5400 6.7100 6.8000 6.8700 7.1000 7.3533 8.1032 9.0265...
9.7520 13.5191 12.7585 11.8784 10.5339 9.6431 9.0825 5.8300 5.5700 5.3700 5.3300 5.2900 5.2500 4.7900 4.6700 4.6300 4.6100 4.4800...
4.3600 4.4600 4.3600 4.5097 5.3665 6.5823 7.9431 16.3444 15.5453 13.4917 11.2298 9.7031 8.6474 3.6500 3.5400 3.4900 3.4900 3.4800...
3.4700 3.0600 3.0200 2.9500 2.9100 2.8700 2.8400 2.4900 2.5200 3.2049 5.3079 7.6541 9.6458 18.2013 16.7009 14.3508 11.7695 10.0188...
8.7262 2.7400 2.6100 2.4400 2.1700 1.9200 1.6900 1.8600 1.6400 1.4400];
a.MPH=[8;10;12;14;16];
A = arrayfun(@(Y) findpeaks(x,'MinPeakHeight',Y.MPH) ,a ) ;
But I get error message saying that MinPeakHeight has to be a scalar:
The problem is that it is precisely MinPeakHeight what I want to change to avoid the for loop...
I might be commiting some syntaxis errors, I tried different things, but I cannot make it work.
Is there a way out of it, or should I stick with the for loop?
  2 Comments
Stephen23
Stephen23 on 1 Jul 2025
"I want to speed up a for loop where I call the function findpeaks, hence I thought of using arrayfun."
A well-written FOR-loop is likely to be faster than ARRAYFUN.
Octavio
Octavio on 2 Jul 2025
Edited: Octavio on 2 Jul 2025
Hi Team (Stephen, John, Steven, Torsten)
Thank for your input.
I did manage to implement the vectorized version of the code with arrayfun following Torsten's advice.
But to my shock I confim that the vectorized code is on average 5-8% slower than the for-loop version.
So not really a good move.

Sign in to comment.

Accepted Answer

Torsten
Torsten on 1 Jul 2025
x=[ 6.9100 6.1800 6.0500 5.7900 5.5000 5.2400 4.9800 4.6800 4.5100 4.6191 5.2582 5.9801 6.9525 13.2387 13.5548 12.1637 10.3495 9.2243...
9.0334 6.3900 6.3300 6.0500 6.1700 6.1100 6.0800 5.0500 5.4400 6.2600 6.5400 6.7100 6.8000 6.8700 7.1000 7.3533 8.1032 9.0265...
9.7520 13.5191 12.7585 11.8784 10.5339 9.6431 9.0825 5.8300 5.5700 5.3700 5.3300 5.2900 5.2500 4.7900 4.6700 4.6300 4.6100 4.4800...
4.3600 4.4600 4.3600 4.5097 5.3665 6.5823 7.9431 16.3444 15.5453 13.4917 11.2298 9.7031 8.6474 3.6500 3.5400 3.4900 3.4900 3.4800...
3.4700 3.0600 3.0200 2.9500 2.9100 2.8700 2.8400 2.4900 2.5200 3.2049 5.3079 7.6541 9.6458 18.2013 16.7009 14.3508 11.7695 10.0188...
8.7262 2.7400 2.6100 2.4400 2.1700 1.9200 1.6900 1.8600 1.6400 1.4400];
a.MPH=[8;10;12;14;16];
A = arrayfun(@(Y) findpeaks(x,'MinPeakHeight',Y) ,a.MPH,'UniformOutput',0 )
A = 5×1 cell array
{[13.5548 13.5191 16.3444 18.2013]} {[13.5548 13.5191 16.3444 18.2013]} {[13.5548 13.5191 16.3444 18.2013]} {[ 16.3444 18.2013]} {[ 16.3444 18.2013]}

More Answers (1)

John D'Errico
John D'Errico on 1 Jul 2025
Edited: John D'Errico on 1 Jul 2025
I see this soooo often, people thinking arrayfun is a good way to speed up code. But, is it, really? Arrayfun is a nice tool to apply an implicit loop.
For example...
Mn = @(n) sym(2).^n - 1;
n = primes(750);
timeit(@() arrayfun(@isprime,Mn(n)))
ans =
9.307847450625
timeit(@() isprime(Mn(n)))
ans =
9.368681450625
But, could I have just used a simple loop? Trivially, yes.
tic,for i = 1:numel(n),isprime(Mn(n(i)));end,toc
Elapsed time is 9.406175 seconds.
The loop overhead is quite small, at least compared to the operations internally.
Again, arrayfun just replaces an explicit loop, say a for or a while loop, with an implicit loop, where that loop is generated internally. Did we gain much? NO. And it will be very rare indeed where a tool like arrayfun can give you a significant improvement in processing speed. Arrayfun and cellfun are great tools, don't get me wrong. They can clean up your code, maybe a tiny boost in speed, SOMETIMES.
But if you are spending a lot of effort to gain a 1% improvement in processing time, then you may want to recosnsider where you are investing your programming efforts.
Why then, why do you use a tool like arrayfun? Often, it is a matter of convenience. They allow you to apply a function to an array, then collecting the results in one place very conveniently. For example
N = (2:20)';
Flist = arrayfun(@factor,N,uniformoutput = false)
Flist =
19×1 cell array
{[ 2]}
{[ 3]}
{[ 2 2]}
{[ 5]}
{[ 2 3]}
{[ 7]}
{[ 2 2 2]}
{[ 3 3]}
{[ 2 5]}
{[ 11]}
{[ 2 2 3]}
{[ 13]}
{[ 2 7]}
{[ 3 5]}
{[2 2 2 2]}
{[ 17]}
{[ 2 3 3]}
{[ 19]}
{[ 2 2 5]}
As you can see, it is a very nice, slick way to collect the results of something, where the results will vary in size. And I can apply cellfun to that result now too.
UniqFacs = cellfun(@unique,Flist,'UniformOutput',false)
UniqFacs =
19×1 cell array
{[ 2]}
{[ 3]}
{[ 2]}
{[ 5]}
{[2 3]}
{[ 7]}
{[ 2]}
{[ 3]}
{[2 5]}
{[ 11]}
{[2 3]}
{[ 13]}
{[2 7]}
{[3 5]}
{[ 2]}
{[ 17]}
{[2 3]}
{[ 19]}
{[2 5]}
Again, a nice, clean way to solve a problem. The loops are implicit, so only generated internally. But don't waste sleep on whether those calls saved any CPU time! The only time saved was my own, since it took fewer lines of code to write them. But a for loop is a pretty simple thing to write.
  1 Comment
Steven Lord
Steven Lord on 1 Jul 2025
One of the use cases for arrayfun is in places where you can't put an explicit loop, specifically inside an anonymous function.
IIRC both arrayfun and structfun were introduced at the same time we enhanced cellfun to accept an arbitrary function handle rather than one of a small fixed list of "things to compute", for parity between cell arrays and other types of arrays in terms of "do something to each element" (or in the case of structfun, "each field") of the data input. For backwards compatibility (as explicitly stated on the cellfun documentation page) cellfun still accepts that "small fixed list" as the func input, but you'll note that neither arrayfun nor structfun do.
C = {1, 2:3, [4 5; 6 7]}
C = 1×3 cell array
{[1]} {[2 3]} {2×2 double}
X1 = cellfun('prodofsize', C) % One of the "small fixed list"
X1 = 1×3
1 2 4
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
X2 = cellfun(@numel, C) % Function handle version
X2 = 1×3
1 2 4
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
S = struct('x1', 1, 'x2', [2 3], 'x3', [4 5; 6 7])
S = struct with fields:
x1: 1 x2: [2 3] x3: [2×2 double]
Y1 = structfun(@numel, S) % Allowed
Y1 = 3×1
1 2 4
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Y2 = structfun('prodofsize', S) % Not allowed
Error using structfun
First input must be a function handle.

Sign in to comment.

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Products


Release

R2022a

Community Treasure Hunt

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

Start Hunting!