Page MenuHomec4science

custom_fit.py
No OneTemporary

File Metadata

Created
Thu, May 2, 20:49

custom_fit.py

# Copyright (C) 2018 by the RROMPy authors
#
# This file is part of RROMPy.
#
# RROMPy is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# RROMPy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
#
import numpy as np
import numpy.linalg as la
from rrompy.utilities.exception_manager import RROMPyException, RROMPyWarning
__all__ = ["customFit"]
def customFit(van, y, rcond=None, full=False, w=None):
"""
Least-squares fit of a polynomial to data. Copied from
numpy.polynomial.polynomial.
Parameters
----------
va : array_like, shape (`M`,`deg` + 1)
Vandermonde-like matrix.
y : array_like, shape (`M`,) or (`M`, `K`)
y-coordinates of the sample points. Several sets of sample points
sharing the same x-coordinates can be (independently) fit with one
call to `polyfit` by passing in for `y` a 2-D array that contains
one data set per column.
rcond : float, optional
Relative condition number of the fit. Singular values smaller
than `rcond`, relative to the largest singular value, will be
ignored. The default value is ``len(van)*eps``, where `eps` is the
relative precision of the platform's float type, about 2e-16 in
most cases.
full : bool, optional
Switch determining the nature of the return value. When ``False``
(the default) just the coefficients are returned; when ``True``,
diagnostic information from the singular value decomposition (used
to solve the fit's matrix equation) is also returned.
w : array_like, shape (`M`,), optional
Weights. If not None, the contribution of each point
``(x[i],y[i])`` to the fit is weighted by `w[i]`. Ideally the
weights are chosen so that the errors of the products ``w[i]*y[i]``
all have the same variance. The default value is None.
Returns
-------
coef : ndarray, shape (`deg` + 1,) or (`deg` + 1, `K`)
Polynomial coefficients ordered from low to high. If `y` was 2-D,
the coefficients in column `k` of `coef` represent the polynomial
fit to the data in `y`'s `k`-th column.
[residuals, rank, singular_values, rcond] : list
These values are only returned if `full` = True
resid -- sum of squared residuals of the least squares fit
rank -- the numerical rank of the scaled Vandermonde matrix
sv -- singular values of the scaled Vandermonde matrix
rcond -- value of `rcond`.
For more details, see `linalg.lstsq`.
Raises
------
RankWarning
Raised if the matrix in the least-squares fit is rank deficient.
The warning is only raised if `full` == False. The warnings can
be turned off by:
>>> import warnings
>>> warnings.simplefilter('ignore', RankWarning)
"""
van = np.asarray(van) + 0.0
y = np.asarray(y) + 0.0
# check arguments.
if van.ndim != 2:
raise RROMPyException("expected 2D vector for van")
if van.size == 0:
raise RROMPyException("expected non-empty vector for van")
if y.ndim < 1 or y.ndim > 2:
raise RROMPyException("expected 1D or 2D array for y")
if len(van) != len(y):
raise RROMPyException("expected van and y to have same length")
order = van.shape[1]
# set up the least squares matrices in transposed form
lhs = van.T
rhs = y.T
if isinstance(w, (str, )) and w.upper() == "AUTO":
# Determine the norms of the design matrix rows.
if issubclass(van.dtype.type, np.complexfloating):
w = np.sqrt((np.square(van.real) + np.square(van.imag)).sum(1))
else:
w = np.sqrt(np.square(van).sum(1))
w[w == 0] = 1
w = np.power(w, -1.)
if w is not None:
w = np.asarray(w) + 0.0
if w.ndim != 1:
raise RROMPyException("expected 1D vector for w")
if len(van) != len(w):
raise RROMPyException("expected van and w to have same length")
# apply weights. Don't use inplace operations as they
# can cause problems with NA.
lhs = lhs * w
rhs = rhs * w
# set rcond
if rcond is None:
rcond = len(van)*np.finfo(van.dtype).eps
# Determine the norms of the design matrix columns.
if issubclass(lhs.dtype.type, np.complexfloating):
scl = np.sqrt((np.square(lhs.real) + np.square(lhs.imag)).sum(1))
else:
scl = np.sqrt(np.square(lhs).sum(1))
scl[scl == 0] = 1
# Solve the least squares problem.
c, resids, rank, s = la.lstsq(lhs.T/scl, rhs.T, rcond)
c = (c.T/scl).T
# warn on rank reduction
if rank != order and not full:
msg = "The fit may be poorly conditioned"
RROMPyWarning(msg, np.polynomial.polyutils.RankWarning, stacklevel = 2)
if full:
return c, [resids, rank, s, rcond]
else:
return c

Event Timeline