Reputation: 23134
Here is what I am currently doing, it works but it's a little cumbersome:
x = np.matrix([[1, 1], [2, -3]])
xmax = x.flat[abs(x).argmax()]
Upvotes: 35
Views: 67970
Reputation: 137
A rather standard way using np.argmax
and np.take
, supporting an arbitrary axis argument
def absmax(a, axis=None):
max_abs_indices = np.argmax(np.abs(a), axis=axis, keepdims=True)
if axis is None:
return np.take(a, max_abs_indices).squeeze()
return np.take_along_axis(a, max_abs_indices, axis=axis).squeeze()
A similar implementation for finding the minimum in the original array in terms of the absolute value.
def absmin(a, axis=None):
min_abs_indices = np.argmin(np.abs(a), axis=axis, keepdims=True)
if axis is None:
return np.take(a, min_abs_indices).squeeze()
return np.take_along_axis(a, min_abs_indices, axis=axis).squeeze()
Upvotes: 0
Reputation: 8906
The value you're looking for has to be either x.max()
or x.min()
so you could do
max(x.min(), x.max(), key=abs)
which is similar to aestrivex's solution but perhaps more readable? Note this will return the minimum in the case where x.min()
and x.max()
have the same absolute value e.g. -5
and 5
. If you have a preference just order the inputs to max
accordingly.
EDIT: Just to clarify, the idea is to leverage the numpy
methods to reduce down to just two values and then use the key
feature of the builtin max
to arbitrate, since key
is not supported by the numpy
methods.
Upvotes: 49
Reputation: 131
If you want to get this value for a 2D numpy array, you can also do the following:
x[np.arange(len(x)), np.abs(x).argmax(axis=1)]
For example if your x
looks like this:
x = np.array([[ -1, -10],
[ -40, -5],
[ -10, 15],
[ 11, 35]])
and you want to get the maximum value for each row disregarding the sign, the result would be np.array([-10, -40, 15, 35])
.
Upvotes: 0
Reputation: 2630
The most compact way would probably be:
x_max = x.flat[np.abs(x).argmax()]
By default, the .argmax()
method operates directly on the flattened array (taken from the NumPy documentation). So the operation looks for the maximum absolute value of the n-dimensional array np.abs(x)
.
Upvotes: 10
Reputation: 31
pardon the necro, but i can't seem to comment on JoeCondron's answer.
I like:
max(x.min(), x.max(), key=abs)
but i believe it can be simplified further:
max(x, key=abs)
seems to work for me (or for non-1D) :
max(x.flat, key=abs)
Upvotes: 2
Reputation: 554
I use it
dt = np.random.rand(50000,500)-0.5
# ur
xmax = dt.flat[abs(dt).argmax()] #230 ms
# new
newdt = np.array([dt.min(),dt.max()]) # 56ms
xmax = newdt.flat[abs(newdt).argmax()] # 4ms
it is almost 4 times faster (60 ms against 230)!!
Upvotes: 0
Reputation: 5539
This one computes the absolute max'es fast - respecting an arbitrary axis
argument in the same way as np.max
and np.argmax
themselves do.
def absmaxND(a, axis=None):
amax = a.max(axis)
amin = a.min(axis)
return np.where(-amin > amax, amin, amax)
For long arrays its about 2.5x faster than a.flat[abs(a).argmax()]
even for the simple case axis=None
- because it doesn't render abs() of the original big array.
Upvotes: 10
Reputation: 3127
I was looking for a way to get the signed values of the maximum absolute values of an N-dimensional array along a specified axis, which none of these answers handle. So, I put together a function to do it. No promises, but it works as far as I've tested it:
def maxabs(a, axis=None):
"""Return slice of a, keeping only those values that are furthest away
from 0 along axis"""
maxa = a.max(axis=axis)
mina = a.min(axis=axis)
p = abs(maxa) > abs(mina) # bool, or indices where +ve values win
n = abs(mina) > abs(maxa) # bool, or indices where -ve values win
if axis == None:
if p: return maxa
else: return mina
shape = list(a.shape)
shape.pop(axis)
out = np.zeros(shape, dtype=a.dtype)
out[p] = maxa[p]
out[n] = mina[n]
return out
Upvotes: 6
Reputation: 5280
I think this is a pretty straightforward way, which might be slightly better if code readability is your primary concern. But really, your way is just as elegant.
np.min(x) if np.max(abs(x)) == abs(np.min(x)) else np.max(x)
Upvotes: -1
Reputation: 19547
The only thing that I could think of, which looks even worse, is:
xmax=x[np.unravel_index(abs(x).argmax(), x.shape)]
Upvotes: 1
Reputation: 2058
EDIT: My answer is off-topic, sorry. As Ophion pointed out this would return the index, not the value - you have to use flat
with my "xmax
" (which is really "xmaxInd
") to get the proper value. Ergo I think your solution is best.
After experimenting a bit I realized you can just do this:
x = np.matrix([[1,1], [2,-3]])
absX = abs(x)
xmax = argmax(absX)
It seems that numpy allows you to take the abs
as well as the argmax
of a matrix. How convenient!
timeit
checks:
def meth1():
x = np.matrix([[1,1],[2,-3]])
xmax = x.flat[abs(x).argmax()]
def meth2():
x = np.matrix([[1,1],[2,-3]])
xmax = argmax(abs(x))
t1 = timeit.Timer("meth1()","from __main__ import meth1")
t2 = timeit.Timer("meth2()","from __main__ import meth2")
mean(t1.repeat(1,100000))
gives Out[99]: 7.854323148727417
mean(t2.repeat(1,100000))
gives Out[98]: 7.7788529396057129
So meth2()
is slightly faster. Probably because it doesn't involve calling flat
.
Upvotes: 3