Reputation: 369
I have a Pandas DataFrame with columns containing x, y, and z-values.
import pandas as pd
df = pd.DataFrame({'Age': x,
'Mileage': y,
'Price': z})
Using scipy.optimize.curvefit()
I'm able to fit a univariate exponential function y = exp(-bx)
:
import numpy as np
from scipy.optimize import curve_fit
# fit y to x
def exp_function(x, a, b):
return a * np.exp(-b * x)
popt, pcov = curve_fit(exp_function, df['Age'], # x-values
df['Price'], # y-values
absolute_sigma=False, maxfev=1000)
# popt
# array([2.81641498e+04, 1.29183078e-01]) # a, b-values
But when I try to extend the same analysis to 3D, I encounter a TypeError
:
# fit z to (x, y)
def exp_function_2(x, y, a, b, c):
return (a/2) * (np.exp(-b * x) + np.exp(-c * y))
popt, pcov = curve_fit(exp_function_2,
df['Age'], # x-values
df['Mileage'], # y-values
df['Price'], # z-values
absolute_sigma=False, maxfev=1000)
# TypeError: exp_function_2() takes 5 positional arguments but 1518 were given
Seems like it thinks I'm passing 1518 arguments (the length of my Pandas dataframe) into exp_function_2()
.
Why does my code work for the 2D (x, y)
fit but get hung up on the 3D (x, y, z)
fit?
Upvotes: 0
Views: 186
Reputation: 6440
You are calling the method with the incorrect arguments.
The docs indicate that the prototype is curve_fit(f, xdata, ydata, p0=None, ...)
, where p0
is the starting guess for the parameters of your function. So in the case when you have a TypeError
, you are passing all 1518 elements of your frame as the default parameters to your function, which of course only accepts 5 arguments. The fact that your code works in the 2D case is a happy coincidence of not using the p0
keyword-argument at all.
You need to pass both the predictors as a single argument in xdata
, and then unpack them inside the exponential function. Something like this (though I'm not sure I have the dataframe indexing correct, I rarely use pandas):
def exp_function_2(x, a, b, c):
return (a/2) * (np.exp(-b * x['Age']) + np.exp(-c * x['Mileage']))
Upvotes: 2