Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi-variable nonlinear regression with unequal length vectors

I am trying to fit some data to a non-linear model with two independent variables, but the length of vectors for the two independent variables are, that is xdat is smaller than ydat.

This is closely related to this question: Python curve_fit with multiple independent variables, but the requirement that xdat and ydat are different sizes seems to break things.

Let's take the example solution of xnx, but change the length of one of the arrays:

import numpy as np
from scipy.optimize import curve_fit

def func(X, a, b, c):
    x,y = X
    return np.log(a) + b*np.log(x) + c*np.log(y)

# some artificially noisy data to fit
x = np.linspace(0.1,1.1,101)
y = np.linspace(1.,2., 90) #I have changed the length of one of these arrays
a, b, c = 10., 4., 6.
z = func((x,y), a, b, c) * 1 + np.random.random(101) / 100

# initial guesses for a,b,c:
p0 = 8., 2., 7.
print curve_fit(func, (x,y), z, p0)

if you do this, then you end up with the error:

ValueError: operands could not be broadcast together with shapes (101,) (90,)

Is there a way to force curve fit to take arrays of different lengths?

like image 323
Jiles Avatar asked Sep 15 '26 21:09

Jiles


1 Answers

There are two problems, the first one is, that your function has to return a 1d-array in order to be used by curve_fit. You can use ravel() from numpy to achieve that. To get the original shape back, you can use reshape(xdim, ydim).

The other thing is the dimensions of your independent variables. You have to generate a complete grid, not only two vectors. You can use meshgrid() to do this.

import numpy as np
from scipy.optimize import curve_fit

def func(X, a, b, c):
    x,y = X
    result = np.log(a) + b*np.log(x) + c*np.log(y)
    return result.ravel()

xdim = 101
ydim = 90    

x = np.linspace(0.1,1.1,xdim)
y = np.linspace(1.,2., ydim)
X=np.meshgrid(x,y)
a, b, c = 10., 4., 6.
z = func(X, a, b, c) * 1 + np.random.random(xdim*ydim) / 100

p0 = 8., 2., 7.
print(curve_fit(func, X, z, p0))

This results in a=10.05005705, b=4.00004791, c=6.00011176.

like image 187
CodeZero Avatar answered Sep 18 '26 11:09

CodeZero



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!