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?
Asked
Active
Viewed 1,819 times
5 Answers
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
-
1As discovered in http://stackoverflow.com/q/28836231/901925 the `log` is evaluated at all values, not just the positive ones. – hpaulj Mar 18 '15 at 20:29
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
-
1Check 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
-
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