Kaila Kaila - 27 days ago 19
Python Question

Numpy log10 function: AttributeError: 'float' object has no attribute 'log10'

import numpy as np
import astropy as ap

def mass(FWHM, lumi):
abs_lumi = bhm.L_1450(lumi)
s1 = (FWHM/1000)
s2 = ((abs_lumi)/(10**44))
s = [(s1**2)*(s2**0.53)]
#mass = np.log10((s1**2)*(s2**0.53)) + 6.66 #old way, didn't work
mass = np.log10(s) + 6.66
return mass


I'm trying to use the numpy log10 function, but I keep getting an error that reads:

AttributeError: 'float' object has no attribute 'log10'


I tried putting my argument into a list (s variable), but I got the same error message. FWHM and lumi are both numbers with decimal points (I think they're called floating point numbers).

Answer

The answer to this is a bit tricky and requires a bit of knowledge how Python handles integers and how numpy coerces types. Thanks @ali_m for your comment!

Assuming 64 bit integer the biggest representable integer is 9,223,372,036,854,775,807 (see for example Wikipedia) which is roughly 10**19. But Python falls back to unlimited integer representations as soon as this value is exceeded (like in your case 10**44). But this unlimited precision type is not nativly supported by NumPy, so results will fall back to objects and these object arrays don't support all (any?) ufuncs, like np.log10.

The solution is simple: Convert this large number to a floating point number:

>>> # Negative powers will result in floats: 44 -> -44, * instead of /
>>> np.array([10, 20]) * 10**-44
array([  1.00000000e-43,   2.00000000e-43])

>>> # you could also make the base a float: 10 -> 10.
>>> np.array([10, 20]) / 10.**44
array([  1.00000000e-43,   2.00000000e-43])

>>> # or make the exponent a float: 44 -> 44.
>>> np.array([10, 20]) / 10**44.
array([  1.00000000e-43,   2.00000000e-43])

>>> # manually cast the result to a float
>>> np.array([10, 20]) / float(10**44)
array([  1.00000000e-43,   2.00000000e-43])

>>> # not working, result is an object array which cannot be used for np.log10
>>> np.array([10, 20]) / (10**(44))
array([1e-43, 2e-43], dtype=object)
>>> #                       ^---------that's the problem!

All you need is to change the third line in your function:

import numpy as np

def mass(FWHM, lumi):
    s1 = FWHM / 1000
    s2 = lumi * 10**-44   # changed line, using the first option.
    s = s1**2 * s2**0.53
    mass = np.log10(s) + 6.66
    return mass

This works at least with all my test inputs, for example:

>>> mass(np.array([10., 20]), np.array([10., 20]))
array([-20.13      , -19.36839411])