Argmax returns wrong value

I have an array of n vectors (of varying length) that I am searching for the largest value. For this I first find the vector containing the largest value with argmax(array) and then find the index of that value with argmax(array[vector]). For one array of 6 vectors with values between 4 and 16.75 this reliably works. For another array of 8 Vectors with values between 4.25 and 34 it finds a relatively high value but not the highest overall. The arrays/vectors are only filled with Float64s and the value returned is not NaN.
Does anyone have an idea why this happens?

can you give an example where it returns incorrect results?

In Julia, arrays are ordered lexicographically… Comparring two arrays will give the largest array in a lexicographic order, not the highest value. The same goes for comparing values in an array of arrays.

julia> x = [1, 100]; y = [3, 4];

julia> x > y
false

julia> y > x
true

julia> t = [x, y];

julia> argmax(t)
2
1 Like

You could use

x = [1, 100]; y = [3, 4];
t = [x, y];
maxval, ind = findmax(maximum, t)
loc = findfirst(==(maxval), t[ind])
2 Likes

When the right value is returned my array consists of 6 vectors, containing 30-50 values ranging between 4 and 16.75. When the wrong value is returned the array consists of 8 vectors, containing between 110-118 values between 4.5 and 34. Here argmax finds neither the longest vector (number 2) nor the one containing the highest value (number 8) but instead vector number 6. This contains 115 values with the highest being 32.75

Do you have some example code that we can run to reproduce this?

Based on your description I think @pdeffebach have given the reason, though it is would be easier to say for sure with some code to look at.

The description of all the different inputs aren’t really that relevant. The point is that this code

is wrong. It does not find the vector with the largest element. It doesn’t matter that it returns the desired result occasionally, by pure chance.

You can use findmax(maximum, array) instead, as shown in my code example.

1 Like

In the documentation argmax is defined as:

  argmax(A; dims) -> indices

  For an array input, return the indices of the maximum elements over the given dimensions. NaN is treated as greater
  than all other values except missing.

  Examples
  ≡≡≡≡≡≡≡≡≡≡

  julia> A = [1.0 2; 3 4]
  2×2 Matrix{Float64}:
   1.0  2.0
   3.0  4.0

  julia> argmax(A, dims=1)
  1×2 Matrix{CartesianIndex{2}}:
   CartesianIndex(2, 1)  CartesianIndex(2, 2)

  julia> argmax(A, dims=2)
  2×1 Matrix{CartesianIndex{2}}:
   CartesianIndex(1, 2)
   CartesianIndex(2, 2)

It returns the maximum elements over given dimensions of an array, not array of vectors. If you can shape your vectors in the same length and create a matrix by concatenating them, then you can get the maximum values you are looking for using argmax.

This worked for me, thanks!

It is always possible to keep things simple (:stuck_out_tongue_winking_eye:) with:

julia> x = [1, 100]; y = [3, 4];
julia> t = [x, y];
julia> Iterators.flatten(
         Iterators.map(
           (x,y)->Iterators.map(tuple,x,Iterators.repeated(y)),
           Iterators.map(x->Iterators.map(reverse,x),enumerate.(t)),
           Iterators.countfrom(1)
         )
       ) |>  maximum
((100, 2), 1)

The actual benefit this has is: 1. Not going through one vector twice which maximum and findfirst can ; 2. This can work if the inputs are iterators.

1 Like

What about

findmax(findmax(y) for y in t)

:smile:

1 Like

Seems like a simple loop would be more readable :wink:

Really elegant :slight_smile: The only thing is that if two vectors have the same maximum element, it will select the last one, which is, I think, not the most common behaviour. Selecting the first among several equal elements is the norm.

I think that it will select the one in which the common element appear first, which, admittedly, is even less common behavior :joy:

The following code is not the most efficient, but it illustrates what I would expect as result:

vv = [[9, 3, 9, 0], [1, 9, 2], [0, -1]]
mx = maximum(reduce(vcat,vv))       # mx = 9
loc = @. findall(==(mx), vv)

# result:
3-element Vector{Vector{Int64}}:
[1, 3]
[2]
[]
1 Like