2

I have this function to compute some sort of polynomial:

def pipoly(df,pj):
    n=np.size(pj)
    p=pj[0]
    for j in range(1,n):
        p+=pj[j]*df**j
    return p

pj is supposed to be an array that contains the initial guesses of the coefficients of the polynomial; the degree of the polynomial is hence determined by the function itself in the first line. df is a scalar variable. This function is passed to scipy.optimize's curve_fit as

parfit,covfig=curve_fit(pipoly,[f-f0[j] for f in f_df[if0[j]:if0[i]]],
                            pmode_xp[ph][if0[j]:if0[i]],
                            p0=([pmode0[ph][-1],(pmode_xp[ph][if0[i]]-pmode_xp[ph][if0[j]])/df]))

The first two arguments after the name of the function are arrays (1D slices of 2D arrays), and I have confirmed that they have the same length. The third argument after pipoly is supposed to be a tuple with the initial guesses for pj, which I printed out before: [0.4586590267346888, 0.7419930843896957]. So why is Python complaining that TypeError: pipoly() takes 2 positional arguments but 3 were given? And if I remove the p0 argument, I'm told that the pj is considered a scalar and can therefore not have an index. How do I make it clear to pipoly that pj is to be an array?

TomR
  • 133
  • 1
  • 14

1 Answers1

1

Your statement:

pj is supposed to be an array that contains the coefficients of the polynomial;

is wrong. According to curve_fit() docs:

scipy.optimize.curve_fit(f, xdata, ydata, p0=None, sigma=None, absolute_sigma=False, check_finite=True, bounds=(-inf, inf), method=None, jac=None, **kwargs)[source] Use non-linear least squares to fit a function, f, to data.

Assumes ydata = f(xdata, *params) + eps

That means that your pipoly() function, to be used by curve_fit() must take a number of arguments equal to the number of parameters of you polynomial plus one (the variable, which is the first argument).
The error:

TypeError: pipoly() takes 2 positional arguments but 3 were given?

is telling you that pipoly receives 3 arguments because you probably were testing a linear polinomyal, so the three arguments were the independent variable and two parameter (the [f-f0[j] for f in f_df[if0[j]:if0[i]]] stuff is a 2-length list).
As you write it, instead it takes 2 argument only.

You can easily solve your problem by adding an asterisk before pj:

def pipoly(df,*pj):
    n=len(pj) #len() is sufficient here, but np.size() works too.
    p=pj[0]
    for j in range(1,n):
        p+=pj[j]*df**j
    return p

This way your function accepts a variable number of arguments. Here more on the meaning and the use of the asterisk in python function parameters.

Valentino
  • 7,291
  • 6
  • 18
  • 34
  • I have edited my post to clarify that the pj are supposed to contain the *initial guess* for the parameters (i.e., the coefficients). Yes, in the example I'm trying a linear function. However, if I change the definition of pipoly as you suggest, the result is not a single number as required but a sequence. – TomR Mar 04 '19 at 14:57
  • That's also incorrect. It simply represents the parameter of you polynomial whose values you want to estimate. You provide the initial guesses in `curve_fit()` (the `p0`). And yes, the result is a sequence containing the estimated values of your parameters. Why do you expect the result to be a single number? – Valentino Mar 04 '19 at 15:02
  • `pipoly` is the fitting model, which is supposed to return a single value for every `df`. In other words, when `curve_fit` yields a set of parameters in `parfit` as the result from the fitting, I should be able to pass theses parameters in a call like `pipoly(0.2,parfit)` so that the function value of `pipoly` for 0.2 according to the optimized parameter set is returned. – TomR Mar 04 '19 at 15:29
  • Because you did not unpack the parameter list. Try this: `y = pipoly(0.2, *parfit)` (note the asterisk, again. Read the link in my answer). `y` is your expected result. – Valentino Mar 04 '19 at 15:47