Question

Is there an efficient way to write a log-like function for a numpy array that gives -inf for negative numbers?

The behaviour I would like is:

>>> log_inf(exp(1))
1.0

>>> log_inf(0)
-inf

>>> log_inf(-1)
-inf

with -inf returned for any negative numbers.

EDIT: At the moment I am using clip to substitute negative numbers for 0, it works but is it efficient?

Was it helpful?

Solution 2

For numpy arrays you can calculate the log and then apply a simple mask.

>>> a=np.exp(np.arange(-3,3,dtype=np.float))
>>> b=np.log(a)
>>> b
array([-3., -2., -1.,  0.,  1.,  2.])

>>> b[b<=0]=-np.inf
>>> b
array([-inf, -inf, -inf, -inf,   1.,   2.])

To save a bit of time and to have the option of calling in place or creating a new array:

def inf_log(arr,copy=False):
    mask= (arr<=1)
    notmask= ~mask
    if copy==True:
        out=arr.copy()
        out[notmask]=np.log(out[notmask])
        out[mask]=-np.inf
        return out
    else:
        arr[notmask]=np.log(arr[notmask])
        arr[mask]=-np.inf

OTHER TIPS

You could use numpy.log with a conditional test for negative numbers:

import numpy as np
def log_inf(x):
    return np.log(x) if x>0 else -float('Inf')


log_inf(-1)
-inf
log_inf(0)
-inf
log_inf(np.exp(1))
1.0

With type checking:

def log_inf(x):
    if not isinstance(x, (list, tuple, np.ndarray)):
        return np.log(x) if x>0 else -float('Inf')
    else:
        pass #could insert array handling here

Given for instance a base 10 log where log(x) is the inverse of 10**x=100, it is mathematically impossible to achieve 10**(-inf)==-1.

But it is possible to achieve 10**(-inf)==0. In numpy you already get:

np.log(0)==-np.inf
#True

and:

10**(-np.inf)==0
#True

Another possible solution is:

np.nan_to_num(np.log(data), neginf=0)

Or for many purposes, using a Numpy masked array may work well:

np.ma.log(data)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top