simultaneous fitting python parameter sharing
<p>I have six datasets, I wish to fit all six datasets simultaneously, with two parameters common between the six datasets and one to be fit seperately.</p>

<p>I'm planning to fit a simple ax**2+bx+c polynomial to the datasets, where a and b is shared between the six datasets and the offset, c, is not shared between the six. </p>

<p>Therefore I'm fitting a common slope between the datasets but with a variable offset.</p>

<p>I'm fully competent in fitting them individually, however as the slopes are similar between each dataset, the error on the offset, c, would be greatly improved using simultaneous fitting.</p>

<p>I typically fit using the scipy.optmize.curve_fit.</p>

<pre><code>import numpy as np
from scipy.optimize import curve_fit

def func(x,a,b,c):
    return (a*(x**2)+b*x+c)
def fit(x,y,yerr):
    popt, pcov = curve_fit(func,x,y,p0=[-0.6,5,-12],sigma=yerr)
    chi=np.sum( ((func(x, *popt) - y) / yerr)**2)
    redchi=(chi-1)/len(y)
    return popt,pcov,redchi,len(y)
</code></pre>

<p>I'm handling 6 sets of: x,xerr,y,yerr
len(x) and len(y) is different for each set.</p>

<p>I understand I have to concatenate the datasets and fit them this way.</p>

<p>If anyone can offer any advice or help, I'm sure it would be beneficial for both me and the community.</p>

<p>Because I had similar fitting problems, I made <a href="http://symfit.readthedocs.io/en/latest/fitting_types.html#global-fitting" rel="nofollow"><code>symfit</code></a> to deal with this kind of scenario. So I'm sorry for shamelessly suggesting my own package but I think it would be very helpful for you. It wraps curve fit but provides a symbolic interface to make things easier.</p>

<p>Your problem could be solved like this:
</p>

<pre><code>from symfit import variables, parameters, Fit

xs = variables('x_1, x_2, x_3, x_4, x_5, x_6')
ys = variables('y_1, y_2, y_3, y_4, y_5, y_6')

a, b = parameters('a, b')
cs = parameters(', '.join('c_{}'.format(i) for i in range(6)))

model_dict = {
    y: a * x**2 + b * x + c
        for x, y, c in zip(xs, ys, cs)
}

fit = Fit(model_dict, x_1=x1_data, x_2=x2_data, ..., y_1=y1_data, ..., sigma_y_1=y1_err, sigma_y_2=y2_err, ...)
fit_result = fit.execute()
print(fit_result)
</code></pre>

<p>Check out the docs for more:
<a href="http://symfit.readthedocs.io/en/latest/fitting_types.html#global-fitting" rel="nofollow">http://symfit.readthedocs.io/en/latest/fitting_types.html#global-fitting</a></p>

<p>p.s. to give initial guesses to your parameters, each <code>Parameter</code> object comes with a <code>.value</code> attribute which holds the initial guess. So for example, <code>a.value = -0.6</code>.</p>

<p><strong>Edit:</strong>
Apperently <code>symfit</code> currently needs all the datasets  to be the same shape. As a workaround you could define the following object:</p>

<pre><code>from symfit import Minimize

class GlobalLeastSquares(Minimize):
    def __init__(self, model, *args, **kwargs):
        try:
            super(GlobalLeastSquares, self).__init__(model, *args, **kwargs)
        except TypeError:
            # Minimize currently enforces scalar functions, let's ignore that
            self.constraints = []

    def error_func(self, p, data):
        """
        Least Squares optimalization.

        :param p: array of floats for the parameters.
        :param data: data to be provided to ``Variable``'s.
        """
        evaluated_func = self.model(*(list(data) + list(p)))
        chi2 = 0
        for component_name, component_data in evaluated_func._asdict().items():
            ydata = self.dependent_data[component_name]
            sigma_data = self.sigma_data['sigma_{}'.format(component_name)]
            chi2 += np.sum((component_data - ydata)**2/sigma_data**2)
        return chi2

    eval_jacobian = False
</code></pre>

<p>Use this object instead of the default <code>Fit</code>, so change</p>

<pre><code>fit = Fit(model_dict, x_1=x1_data, x_2=x2_data, ..., y_1=y1_data, ..., sigma_y_1=y1_err, sigma_y_2=y2_err, ...)
</code></pre>

<p>to</p>

<pre><code>fit = GlobalLeastSquares(model_dict, x_1=x1_data, x_2=x2_data, ..., y_1=y1_data, ..., sigma_y_1=y1_err, sigma_y_2=y2_err, ...)
</code></pre>

<p>I will make sure this functionality is wrapped into <code>Fit</code> in the next version of <code>symfit</code> (and massively generalized and cleaned up).</p>

python curve-fitting least-squares data-fitting