James
James

Reputation: 11

Curve fitting with scipy - I am getting type errors

I read some x and y data from a file, convert to a float and put in separate arrays, then call a curve-fitting function from scipy.

It gives me different error messages depending on which equation I use (in the defined function). I have commented on the code after the equation I want to use, it is the top, uncommented equation (line 9).

I can understand why it might want a float rather than a string, yet my attempts at type-casting don't seem to have worked. My most common error is TypeError: a float is required

If I try to pass it values not from reading in my file, but using np.linspace as in an example I found on the scipy website, it gives me a different error.

I have commented errors on the code, I hope you find it unambiguous. I have also pasted the input text file I am using.

import sys
import numpy as np
import math as m
from scipy.optimize import curve_fit


def func( x, a, b ):
  return a*m.pow( x, 2 )*np.exp( -b*x );    #the function I want!: line 9 in funcTypeError:     a float is required
  #return a*m.exp(-b*x)         #line 10 in func TypeError: a     float is required
  #return a*np.exp(-b*x)            #Example equation. line 444 in _general_function   
                                    #ValueError:operands could not be broadcast together with shapes
  #return a*b*m.pow( x, 2 );            #line 10 in func TypeError: a float is required

#end def 

file = sys.argv[1];

f = open( file );
y_array = [];
x_array = [];

for line in f:
    words = line.split();           
    x = words[0].rstrip('\r\n');
    y = words[1].rstrip('\r\n');
    x_array.append( float( x ) );
    y_array.append( float( y ) );
#end for
#data = f.read();

popt, pcov = curve_fit( func, x_array, y_array );

OR I try this from the example they give on the scipy website, with my above, uncommented, desired equation

x = np.linspace(0,4,50)
y = func(x, 2.5, 1.3 )
yn = y + 0.2*np.random.normal(size=len(x))
popt, pcov = curve_fit(func, x, yn)

#TypeError: only length-1 arrays can be converted to Python scalars.

input file (just a few lines, there is more). Two columns of numbers

352 28
423 30
494 32
565 3
636 0
707 0

Upvotes: 1

Views: 885

Answers (1)

DSM
DSM

Reputation: 353199

Your x is a list, and you're calling math.pow on it. math.pow only knows to how raise things which are floats or convertable to floats. Thus, TypeError: a float is required. That's one of the reasons we have numpy. :^)

We can make this much simpler by working with numpy throughout. Then we can simply use ** to take the power of the whole array.

def func( x, a, b ):
    return a * x**2 * np.exp( -b*x )

file = sys.argv[1]
x,y = np.loadtxt(file, unpack=True)
popt, pcov = curve_fit( func, x, y)

gives me

>>> popt
array([ 1.,  1.])
>>> pcov
inf

with your data, which isn't very well fit by that function. The example works much better:

>>> x = np.linspace(0,4,50)
>>> y = func(x, 2.5, 1.3 )
>>> yn = y + 0.2*np.random.normal(size=len(x))
>>> popt, pcov = curve_fit(func, x, yn)
>>> popt
array([ 3.15537828,  1.43218611])
>>> pcov
array([[ 0.08045745,  0.01257863],
       [ 0.01257863,  0.00232191]])

Upvotes: 4

Related Questions