models.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. """ Collection of Model instances for use with the odrpack fitting package.
  2. """
  3. from __future__ import division, print_function, absolute_import
  4. import numpy as np
  5. from scipy.odr.odrpack import Model
  6. __all__ = ['Model', 'exponential', 'multilinear', 'unilinear', 'quadratic',
  7. 'polynomial']
  8. def _lin_fcn(B, x):
  9. a, b = B[0], B[1:]
  10. b.shape = (b.shape[0], 1)
  11. return a + (x*b).sum(axis=0)
  12. def _lin_fjb(B, x):
  13. a = np.ones(x.shape[-1], float)
  14. res = np.concatenate((a, x.ravel()))
  15. res.shape = (B.shape[-1], x.shape[-1])
  16. return res
  17. def _lin_fjd(B, x):
  18. b = B[1:]
  19. b = np.repeat(b, (x.shape[-1],)*b.shape[-1],axis=0)
  20. b.shape = x.shape
  21. return b
  22. def _lin_est(data):
  23. # Eh. The answer is analytical, so just return all ones.
  24. # Don't return zeros since that will interfere with
  25. # ODRPACK's auto-scaling procedures.
  26. if len(data.x.shape) == 2:
  27. m = data.x.shape[0]
  28. else:
  29. m = 1
  30. return np.ones((m + 1,), float)
  31. def _poly_fcn(B, x, powers):
  32. a, b = B[0], B[1:]
  33. b.shape = (b.shape[0], 1)
  34. return a + np.sum(b * np.power(x, powers), axis=0)
  35. def _poly_fjacb(B, x, powers):
  36. res = np.concatenate((np.ones(x.shape[-1], float), np.power(x,
  37. powers).flat))
  38. res.shape = (B.shape[-1], x.shape[-1])
  39. return res
  40. def _poly_fjacd(B, x, powers):
  41. b = B[1:]
  42. b.shape = (b.shape[0], 1)
  43. b = b * powers
  44. return np.sum(b * np.power(x, powers-1),axis=0)
  45. def _exp_fcn(B, x):
  46. return B[0] + np.exp(B[1] * x)
  47. def _exp_fjd(B, x):
  48. return B[1] * np.exp(B[1] * x)
  49. def _exp_fjb(B, x):
  50. res = np.concatenate((np.ones(x.shape[-1], float), x * np.exp(B[1] * x)))
  51. res.shape = (2, x.shape[-1])
  52. return res
  53. def _exp_est(data):
  54. # Eh.
  55. return np.array([1., 1.])
  56. multilinear = Model(_lin_fcn, fjacb=_lin_fjb,
  57. fjacd=_lin_fjd, estimate=_lin_est,
  58. meta={'name': 'Arbitrary-dimensional Linear',
  59. 'equ':'y = B_0 + Sum[i=1..m, B_i * x_i]',
  60. 'TeXequ':r'$y=\beta_0 + \sum_{i=1}^m \beta_i x_i$'})
  61. def polynomial(order):
  62. """
  63. Factory function for a general polynomial model.
  64. Parameters
  65. ----------
  66. order : int or sequence
  67. If an integer, it becomes the order of the polynomial to fit. If
  68. a sequence of numbers, then these are the explicit powers in the
  69. polynomial.
  70. A constant term (power 0) is always included, so don't include 0.
  71. Thus, polynomial(n) is equivalent to polynomial(range(1, n+1)).
  72. Returns
  73. -------
  74. polynomial : Model instance
  75. Model instance.
  76. """
  77. powers = np.asarray(order)
  78. if powers.shape == ():
  79. # Scalar.
  80. powers = np.arange(1, powers + 1)
  81. powers.shape = (len(powers), 1)
  82. len_beta = len(powers) + 1
  83. def _poly_est(data, len_beta=len_beta):
  84. # Eh. Ignore data and return all ones.
  85. return np.ones((len_beta,), float)
  86. return Model(_poly_fcn, fjacd=_poly_fjacd, fjacb=_poly_fjacb,
  87. estimate=_poly_est, extra_args=(powers,),
  88. meta={'name': 'Sorta-general Polynomial',
  89. 'equ': 'y = B_0 + Sum[i=1..%s, B_i * (x**i)]' % (len_beta-1),
  90. 'TeXequ': r'$y=\beta_0 + \sum_{i=1}^{%s} \beta_i x^i$' %
  91. (len_beta-1)})
  92. exponential = Model(_exp_fcn, fjacd=_exp_fjd, fjacb=_exp_fjb,
  93. estimate=_exp_est, meta={'name':'Exponential',
  94. 'equ': 'y= B_0 + exp(B_1 * x)',
  95. 'TeXequ': r'$y=\beta_0 + e^{\beta_1 x}$'})
  96. def _unilin(B, x):
  97. return x*B[0] + B[1]
  98. def _unilin_fjd(B, x):
  99. return np.ones(x.shape, float) * B[0]
  100. def _unilin_fjb(B, x):
  101. _ret = np.concatenate((x, np.ones(x.shape, float)))
  102. _ret.shape = (2,) + x.shape
  103. return _ret
  104. def _unilin_est(data):
  105. return (1., 1.)
  106. def _quadratic(B, x):
  107. return x*(x*B[0] + B[1]) + B[2]
  108. def _quad_fjd(B, x):
  109. return 2*x*B[0] + B[1]
  110. def _quad_fjb(B, x):
  111. _ret = np.concatenate((x*x, x, np.ones(x.shape, float)))
  112. _ret.shape = (3,) + x.shape
  113. return _ret
  114. def _quad_est(data):
  115. return (1.,1.,1.)
  116. unilinear = Model(_unilin, fjacd=_unilin_fjd, fjacb=_unilin_fjb,
  117. estimate=_unilin_est, meta={'name': 'Univariate Linear',
  118. 'equ': 'y = B_0 * x + B_1',
  119. 'TeXequ': '$y = \\beta_0 x + \\beta_1$'})
  120. quadratic = Model(_quadratic, fjacd=_quad_fjd, fjacb=_quad_fjb,
  121. estimate=_quad_est, meta={'name': 'Quadratic',
  122. 'equ': 'y = B_0*x**2 + B_1*x + B_2',
  123. 'TeXequ': '$y = \\beta_0 x^2 + \\beta_1 x + \\beta_2'})