Search code examples
pythonnumpyscipyleast-squares

TypeError: fun() takes 1 positional argument but 2 were given error in sciply.optimize.curve_fit


I am attempting to use scipy.optimize.curve_fit but appear to be coming across some issues. Here is my code:

import numpy as np
import matplotlib.pyplot as plt
import os
os.chdir('C:/Users/Sams PC/Desktop/')
data1=np.loadtxt('Titrations6.txt')
data2=np.loadtxt('Concentrations3.txt')
protein=data2[:,0]
ligand=data2[:,1]
b=data1.transpose()
for x in b:
    def fun(kd):
        return np.array((B+kd-(np.sqrt(((B+kd)**2)-4*A*C)))/2*A)

    from scipy.optimize import curve_fit
    intensity=[x]
    xdata=[protein,ligand]
    ydata=intensity
    A=xdata[0]
    B=xdata[0]+xdata[1]
    C=xdata[1]
    print (xdata)
    print (ydata)
    popt, pcov=curve_fit(fun,xdata,ydata, p0=(1))

Data1 is a 8x6 matrix, and data2 is a 2x6 matrix. I want my function to loop through and fit each column of data1. When I run this I get the following error:

TypeError: fun() takes 1 positional argument but 2 were given

Which I don't quite understand. I've only given fun one argument, but it's saying that it's been infact given 2 arguments. Any help would be greatly appreciated!

Edit: I've added the data I'm using below for some clarity. This is what I Get when I do print (data1) and data2.

[[0.         0.         0.         0.         0.         0.
  0.         0.        ]
 [0.         0.         0.         0.         0.         0.
  0.         0.        ]
 [0.41437697 0.23486582 0.3946243  0.37853352 0.35563582 0.39256528
  0.32845158 0.37614817]
 [0.56069666 0.47530052 0.59725788 0.65505611 0.53696339 0.56234781
  0.59790931 0.61088421]
 [0.80054062 0.6781974  0.79853213 0.88599716 0.80807803 0.84945185
  0.82345173 0.8316841 ]
 [1.         1.         1.         1.         1.         1.
  1.         1.        ]]
[[0.59642147 0.06      ]
 [0.5859375  0.11928429]
 [0.56603774 0.29296875]
 [0.53003534 0.62264151]
 [0.41899441 1.21908127]
 [0.38861986 3.05865922]]

Solution

  • The main issue is you didn't specify any parameters to optimize. See scipy.optimize.curve_fit. Also I'd recommend importing and defining functions outside your loop. The basic form of a model function is:

    def fun(independent_variable, *parameters_to_optimize):
        # return a combination of the independent variable and parameters
    

    An example:

    import matplotlib.pyplot as plt
    import numpy as np
    from scipy.optimize import curve_fit
    
    # Generate some noisy data
    x = np.linspace(0, 10, 1000)
    y = x**2 + 3*x + np.random.normal(0, 0.5, len(x))
    
    # define the model I want to fit
    def fun(x, a, b, c):
        return a + b * x + c * x ** 2
    
    popt, pcov = curve_fit(fun, x, y)
    
    # plot
    plt.plot(x, y, label='data')
    plt.plot(x, fun(x, *popt), label='fitted')
    plt.grid()
    plt.legend()
    print(popt)
    # [-0.07309343  3.01359277  0.99988617]
    

    Plot

    In your example there are two mistakes:

    def fun(kd):
        return np.array((B+kd-(np.sqrt(((B+kd)**2)-4*A*C)))/2*A) 
    
    • For curve_fit there is nothing to optimize in this function, it has only one variable which is assumed to be the independent one.
    • curve_fit expect a numeric output from the model function, not an array

    Without seeing the actual data, that's what I can say.