I am writing code to graph a few different functions, many with exponentials. This is what I have:
>>> from fractions import Fraction
>>> f13=Fraction('1/3')
>>> f23=Fraction('2/3')
>>> f43=Fraction('4/3')
>>> f53=Fraction('5/3')
>>> f12=Fraction('1/2')
>>> f32=Fraction('3/2')
>>> f56=Fraction('5/6')
>>> fm1=Fraction('-1')
>>> fm23=Fraction('-2/3')
>>> fm32=Fraction('-3/2')
>>> from matplotlib import pyplot as plt
>>> import numpy as np
>>> x=np.arange(0.01,2,0.01)
>>> xa=x/(1+0.1071*x)
>>> rate=(4.817e+6)*(x**fm23)*np.exp(-14.964/(x**f13))*(1+0.0325*(x**f13)-(1.04e-3)* (x**f23)-(2.37e-4)*x-(8.11e-5)*(x**f43)-(4.69e-5)*(x**f53))+(5.938e+6)*(xa**f56)*(x**fm32)*np.exp(-12.859/(xa**f13))
And when I enter it, it gives me this error:
Traceback (most recent call last):
File "<pyshell#22>", line 1, in <module>
rate=rate=(4.817e+6)*(x**fm23)*np.exp(-14.964/(x**f13))*(1+0.0325*(x**f13)-(1.04e-3)* (x**f23)-(2.37e-4)*x-(8.11e-5)*(x**f43)-(4.69e-5)*(x**f53))+(5.938e+6)*(xa**f56)*(x**fm32)*np.exp(-12.859/(xa**f13))
AttributeError: exp
However, I have written the same code for this function:
>>> rate=(7.29e+2)+2.40*((10**3)*(x**fm32)*np.exp(-0.223/x))
And it works just fine. Does anyone know what might be wrong?
NumPy types don't mix well with fractions.Fraction
. In the expression x**f13
, x
is a normal NumPy array of dtype float64
, but f13
is Fraction
object. As a result of that, the expression x**f13
is an array with dtype object
, all of whose elements are (regular) Python floats, rather than NumPy floats. This essentially means that NumPy couldn't figure out what type the results should be, so it ends up storing a collection of Python objects rather than a packed efficient homogeneously-typed array.
In the second expression you give, -0.223/x
is a NumPy array of dtype float64
, so there are no issues applying np.exp
to it.
When you apply np.exp
an array of dtype object
, it goes through looking for an exp
method on each element individually, and that gives you the AttributeError
you're seeing. Here's an example:
Python 2.6.9 (unknown, Nov 18 2013, 14:53:18)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> x = np.array([0.1, 0.2], dtype=object)
>>> np.exp(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: exp
Python 2.7.8 gives a slightly better error message that at least mentions the type of the object it failed to find the exp
attribute on:
AttributeError: 'float' object has no attribute 'exp'
It seems this error message was improved at some point between Python 2.7.5 and Python 2.7.8, though I'm not sure when.
Suggested solution: convert your Fraction
instances to float
before combining them with the NumPy arrays:
>>> import numpy as np
>>> from fractions import Fraction
>>> np.exp(np.arange(10) ** Fraction(1, 3)) # Fails as above
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: exp
>>> np.exp(np.arange(10) ** float(Fraction(1, 3))) # Works.
array([ 1. , 2.71828183, 3.52514317, 4.23020126, 4.89102089,
5.52882849, 6.15411272, 6.77291238, 7.3890561 , 8.0051399 ])
Alternatively, avoid the Fraction
type altogether. It doesn't really buy you anything here - the exactness is lost as soon as you combine with floats anyway.
>>> f13 = 1.0 / 3.0 # Look Ma, no fractions!
>>> np.exp(np.arange(10) ** f13)
array([ 1. , 2.71828183, 3.52514317, 4.23020126, 4.89102089,
5.52882849, 6.15411272, 6.77291238, 7.3890561 , 8.0051399 ])