0

SciPy thoughtfully provides the scipy.log function, which will take an array and then log all elements in that array. Is there a way to log only the positive (i.e. positive non-zero) elements of an array?

Kris
  • 177
  • 4
  • Use [boolean indexing](http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#boolean-array-indexing) to select the positive values. – wwii Mar 17 '15 at 18:21

5 Answers5

3

What about where()?

import numpy as np
a = np.array([ 1., -1., 0.5, -0.5, 0., 2. ])
la = np.where(a>0, np.log(a), a) 
print(la)
# Gives [ 0.         -1.         -0.69314718 -0.5         0.          0.69314718]
Dietrich
  • 5,241
  • 3
  • 24
  • 36
1

Here's a vectorized solution that keeps the original array and leaves non-positive values unchanged:

In [1]: import numpy as np
In [2]: a = np.array([ 1., -1., 0.5, -0.5, 0., 2. ])
In [3]: loga = np.log(a)
In [4]: loga
Out[4]: array([ 0., nan, -0.69314718, nan, -inf, 0.69314718 ])

In [5]: # Remove nasty nanses and infses
In [6]: loga[np.where(~np.isfinite(loga))] = a[np.where(~np.isfinite(loga))]
In [7]: loga
Out[7]: array([ 0., -1., -0.69314718, -0.5,  0., 0.69314718])

Here, np.where(~np.isfinite(loga)) returns the indexes of non-finite entries in the loga array, and we replace these values with the corresponding originals from a.

xnx
  • 24,509
  • 11
  • 70
  • 109
  • 1
    Check your answer. Your final output of `loga` is equal to the original `a`. Copy-paste mistake? Also, you should actually have `loga[np.where(~np.isfinite(loga))] = a[np.where(~np.isfinite(loga))]`, otherwise you'll assign the wrong values to the elements where `loga` is not finite. – Warren Weckesser Mar 17 '15 at 22:11
  • You're right @Warren Weckesser: thanks as ever. I was a bit quick to transcribe from my terminal. – xnx Mar 17 '15 at 22:44
  • I think @Dietrich has provided the best answer to this question anyway. – xnx Mar 17 '15 at 22:46
1

With boolean indexing:

In [695]: a = np.array([ 1. , -1. ,  0.5, -0.5,  0. ,  2. ])    
In [696]: I=a>0
In [697]: a[I]=np.log(a[I])
In [698]: a
Out[698]: 
array([ 0.        , -1.        , -0.69314718, -0.5       ,  0.        ,
        0.69314718])

or if you just want to keep the logged terms

In [707]: np.log(a[I])
Out[707]: array([ 0.        , -0.69314718,  0.69314718])
hpaulj
  • 221,503
  • 14
  • 230
  • 353
0

Probably not the answer you're looking for but I'll just put this here:

for i in range(0,rows):
    for j in range(0,cols):
        if array[i,j] > 0:
            array[i,j]=log(array[i,j])    
logic
  • 1,739
  • 3
  • 16
  • 22
  • I was hoping for a way of doing it which didn't need to explicitly loop over all the elements of the array - the array can get quite large. – Kris Mar 17 '15 at 18:19
0

You can vectorize a custom function.

import numpy as np

def pos_log(x):
    if x > 0:
        return np.log(x)
    return x

v_pos_log = np.vectorize(pos_log, otypes=[np.float])

result = v_pos_log(np.array([-1, 1]))
#>>> np.array([-1, 0])

But as the documentation for numpy.vectorize says "The vectorize function is provided primarily for convenience, not for performance. The implementation is essentially a for loop."

axblount
  • 2,639
  • 23
  • 27