10

Wondering whether there are discrete versions of ArgMax / ArgMin, that is, something that will find the part of an expression at which some function f of the elements is maximized (or minimized).

Last[Ordering[f/@list]] and First[Ordering[f/@list]] will do, but the following does not work:

ArgMax[Function[i, (f/@list)[[i]]], i]
Reb.Cabin
  • 8,661
  • 1
  • 34
  • 62
  • 3
    If you use Ordering, Ordering[list, 1] is more efficient than First@Ordering[list] – Szabolcs Feb 11 '13 at 19:40
  • What if the function is bivariate, e.g., f(x,y), and we want to find argmax or argmin over both x and y? – Alex Mar 24 '15 at 18:27
  • If you have a new question, please ask it by clicking the Ask Question button. Include a link to this question if it helps provide context. – bbgodfrey Mar 24 '15 at 18:58
  • This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post - you can always comment on your own posts, and once you have sufficient reputation you will be able to comment on any post. –  Mar 24 '15 at 19:38

3 Answers3

8

I guess Max and Min are the best fit for discrete lists.

f[x_] := x Sin[x];
list = RandomReal[10, 10^6];
(Position[#, Max[#], 2][[1, 1]]) &@(f /@ list)

One can forcefully use NArgMax or NArgMin for this purpose but they are likely to be extremely inefficient! One such example

list = RandomReal[10, 1000];
ob[i_?IntegerQ] := (f /@ list)[[i]];
ob@NArgMax[{Evaluate@ob[x],1<= x<= Length@list&&Element[x,Integers]},x]//AbsoluteTiming

{5.8344103, 7.91672}

Where as

Max[f /@ list]// AbsoluteTiming

{0., 7.91672}

For timing comparison with solution using Ordering see the following plot. Horizontal axes shows the data length of list and the vertical axes is denoting computation time in seconds. I have tested it in an Intel i7 PC with 64 GB RAM.

enter image description here

As one can see if you compile the functions you get even better speed ups.

cf=Compile[{{x,_Real,1}},
      Module[{listval,max},
             listval=# Sin[#]&/@x;
             max=Max[listval];
             (Position[listval,max])[[1,1]]
             ],
      CompilationTarget->"C",
      RuntimeAttributes->{Listable},Parallelization->True];
PlatoManiac
  • 14,723
  • 2
  • 42
  • 74
4

Ordering is good for this if you use a custom ordering function:

f=Sin;
list = RandomReal[{0, Pi}, 100];
First@Ordering[list, 1, f[#1] < f[#2] &]

And similarly for maximum replacing 1 with -1 (or < with >)

ssch
  • 16,590
  • 2
  • 53
  • 88
  • 1
    Manually supplying an ordering function seems to be much slower than just using Ordering[f/@list,1] as kguler recommended in a comment to an answer above. – Wizard Oct 07 '13 at 21:59
3

Version 10 has a new function FindPeaks that can be used here:

f[x_] := x Sin[x];
list = Range[1, 10, 0.1];
FindPeaks[f /@ list]

This returns the location (in the list) and value of the local maxes. Another new function that's related is MaxDetect, which returns a vector of zeros (at all the non-max locations) and ones (at all the max locations).

MaxDetect[f /@ list]

MaxDetect also works nicely on 2D and 3D data arrays and images, and there is also MinDetect that does what you would expect.

bill s
  • 68,936
  • 4
  • 101
  • 191