123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- """ Collection of Model instances for use with the odrpack fitting package.
- """
- import numpy as np
- from scipy.odr._odrpack import Model
- __all__ = ['Model', 'exponential', 'multilinear', 'unilinear', 'quadratic',
- 'polynomial']
- def _lin_fcn(B, x):
- a, b = B[0], B[1:]
- b.shape = (b.shape[0], 1)
- return a + (x*b).sum(axis=0)
- def _lin_fjb(B, x):
- a = np.ones(x.shape[-1], float)
- res = np.concatenate((a, x.ravel()))
- res.shape = (B.shape[-1], x.shape[-1])
- return res
- def _lin_fjd(B, x):
- b = B[1:]
- b = np.repeat(b, (x.shape[-1],)*b.shape[-1], axis=0)
- b.shape = x.shape
- return b
- def _lin_est(data):
- # Eh. The answer is analytical, so just return all ones.
- # Don't return zeros since that will interfere with
- # ODRPACK's auto-scaling procedures.
- if len(data.x.shape) == 2:
- m = data.x.shape[0]
- else:
- m = 1
- return np.ones((m + 1,), float)
- def _poly_fcn(B, x, powers):
- a, b = B[0], B[1:]
- b.shape = (b.shape[0], 1)
- return a + np.sum(b * np.power(x, powers), axis=0)
- def _poly_fjacb(B, x, powers):
- res = np.concatenate((np.ones(x.shape[-1], float),
- np.power(x, powers).flat))
- res.shape = (B.shape[-1], x.shape[-1])
- return res
- def _poly_fjacd(B, x, powers):
- b = B[1:]
- b.shape = (b.shape[0], 1)
- b = b * powers
- return np.sum(b * np.power(x, powers-1), axis=0)
- def _exp_fcn(B, x):
- return B[0] + np.exp(B[1] * x)
- def _exp_fjd(B, x):
- return B[1] * np.exp(B[1] * x)
- def _exp_fjb(B, x):
- res = np.concatenate((np.ones(x.shape[-1], float), x * np.exp(B[1] * x)))
- res.shape = (2, x.shape[-1])
- return res
- def _exp_est(data):
- # Eh.
- return np.array([1., 1.])
- class _MultilinearModel(Model):
- r"""
- Arbitrary-dimensional linear model
- This model is defined by :math:`y=\beta_0 + \sum_{i=1}^m \beta_i x_i`
- Examples
- --------
- We can calculate orthogonal distance regression with an arbitrary
- dimensional linear model:
- >>> from scipy import odr
- >>> import numpy as np
- >>> x = np.linspace(0.0, 5.0)
- >>> y = 10.0 + 5.0 * x
- >>> data = odr.Data(x, y)
- >>> odr_obj = odr.ODR(data, odr.multilinear)
- >>> output = odr_obj.run()
- >>> print(output.beta)
- [10. 5.]
- """
- def __init__(self):
- super().__init__(
- _lin_fcn, fjacb=_lin_fjb, fjacd=_lin_fjd, estimate=_lin_est,
- meta={'name': 'Arbitrary-dimensional Linear',
- 'equ': 'y = B_0 + Sum[i=1..m, B_i * x_i]',
- 'TeXequ': r'$y=\beta_0 + \sum_{i=1}^m \beta_i x_i$'})
- multilinear = _MultilinearModel()
- def polynomial(order):
- """
- Factory function for a general polynomial model.
- Parameters
- ----------
- order : int or sequence
- If an integer, it becomes the order of the polynomial to fit. If
- a sequence of numbers, then these are the explicit powers in the
- polynomial.
- A constant term (power 0) is always included, so don't include 0.
- Thus, polynomial(n) is equivalent to polynomial(range(1, n+1)).
- Returns
- -------
- polynomial : Model instance
- Model instance.
- Examples
- --------
- We can fit an input data using orthogonal distance regression (ODR) with
- a polynomial model:
- >>> import numpy as np
- >>> import matplotlib.pyplot as plt
- >>> from scipy import odr
- >>> x = np.linspace(0.0, 5.0)
- >>> y = np.sin(x)
- >>> poly_model = odr.polynomial(3) # using third order polynomial model
- >>> data = odr.Data(x, y)
- >>> odr_obj = odr.ODR(data, poly_model)
- >>> output = odr_obj.run() # running ODR fitting
- >>> poly = np.poly1d(output.beta[::-1])
- >>> poly_y = poly(x)
- >>> plt.plot(x, y, label="input data")
- >>> plt.plot(x, poly_y, label="polynomial ODR")
- >>> plt.legend()
- >>> plt.show()
- """
- powers = np.asarray(order)
- if powers.shape == ():
- # Scalar.
- powers = np.arange(1, powers + 1)
- powers.shape = (len(powers), 1)
- len_beta = len(powers) + 1
- def _poly_est(data, len_beta=len_beta):
- # Eh. Ignore data and return all ones.
- return np.ones((len_beta,), float)
- return Model(_poly_fcn, fjacd=_poly_fjacd, fjacb=_poly_fjacb,
- estimate=_poly_est, extra_args=(powers,),
- meta={'name': 'Sorta-general Polynomial',
- 'equ': 'y = B_0 + Sum[i=1..%s, B_i * (x**i)]' % (len_beta-1),
- 'TeXequ': r'$y=\beta_0 + \sum_{i=1}^{%s} \beta_i x^i$' %
- (len_beta-1)})
- class _ExponentialModel(Model):
- r"""
- Exponential model
- This model is defined by :math:`y=\beta_0 + e^{\beta_1 x}`
- Examples
- --------
- We can calculate orthogonal distance regression with an exponential model:
- >>> from scipy import odr
- >>> import numpy as np
- >>> x = np.linspace(0.0, 5.0)
- >>> y = -10.0 + np.exp(0.5*x)
- >>> data = odr.Data(x, y)
- >>> odr_obj = odr.ODR(data, odr.exponential)
- >>> output = odr_obj.run()
- >>> print(output.beta)
- [-10. 0.5]
- """
- def __init__(self):
- super().__init__(_exp_fcn, fjacd=_exp_fjd, fjacb=_exp_fjb,
- estimate=_exp_est,
- meta={'name': 'Exponential',
- 'equ': 'y= B_0 + exp(B_1 * x)',
- 'TeXequ': r'$y=\beta_0 + e^{\beta_1 x}$'})
- exponential = _ExponentialModel()
- def _unilin(B, x):
- return x*B[0] + B[1]
- def _unilin_fjd(B, x):
- return np.ones(x.shape, float) * B[0]
- def _unilin_fjb(B, x):
- _ret = np.concatenate((x, np.ones(x.shape, float)))
- _ret.shape = (2,) + x.shape
- return _ret
- def _unilin_est(data):
- return (1., 1.)
- def _quadratic(B, x):
- return x*(x*B[0] + B[1]) + B[2]
- def _quad_fjd(B, x):
- return 2*x*B[0] + B[1]
- def _quad_fjb(B, x):
- _ret = np.concatenate((x*x, x, np.ones(x.shape, float)))
- _ret.shape = (3,) + x.shape
- return _ret
- def _quad_est(data):
- return (1.,1.,1.)
- class _UnilinearModel(Model):
- r"""
- Univariate linear model
- This model is defined by :math:`y = \beta_0 x + \beta_1`
- Examples
- --------
- We can calculate orthogonal distance regression with an unilinear model:
- >>> from scipy import odr
- >>> import numpy as np
- >>> x = np.linspace(0.0, 5.0)
- >>> y = 1.0 * x + 2.0
- >>> data = odr.Data(x, y)
- >>> odr_obj = odr.ODR(data, odr.unilinear)
- >>> output = odr_obj.run()
- >>> print(output.beta)
- [1. 2.]
- """
- def __init__(self):
- super().__init__(_unilin, fjacd=_unilin_fjd, fjacb=_unilin_fjb,
- estimate=_unilin_est,
- meta={'name': 'Univariate Linear',
- 'equ': 'y = B_0 * x + B_1',
- 'TeXequ': '$y = \\beta_0 x + \\beta_1$'})
- unilinear = _UnilinearModel()
- class _QuadraticModel(Model):
- r"""
- Quadratic model
- This model is defined by :math:`y = \beta_0 x^2 + \beta_1 x + \beta_2`
- Examples
- --------
- We can calculate orthogonal distance regression with a quadratic model:
- >>> from scipy import odr
- >>> import numpy as np
- >>> x = np.linspace(0.0, 5.0)
- >>> y = 1.0 * x ** 2 + 2.0 * x + 3.0
- >>> data = odr.Data(x, y)
- >>> odr_obj = odr.ODR(data, odr.quadratic)
- >>> output = odr_obj.run()
- >>> print(output.beta)
- [1. 2. 3.]
- """
- def __init__(self):
- super().__init__(
- _quadratic, fjacd=_quad_fjd, fjacb=_quad_fjb, estimate=_quad_est,
- meta={'name': 'Quadratic',
- 'equ': 'y = B_0*x**2 + B_1*x + B_2',
- 'TeXequ': '$y = \\beta_0 x^2 + \\beta_1 x + \\beta_2'})
- quadratic = _QuadraticModel()
|