Polynomials#
Polynomials in NumPy can be created, manipulated, and even fitted using
the convenience classes
of the numpy.polynomial
package, introduced in NumPy 1.4.
Prior to NumPy 1.4, numpy.poly1d
was the class of choice and it is still
available in order to maintain backward compatibility.
However, the newer polynomial package
is more complete
and its convenience classes provide a
more consistent, better-behaved interface for working with polynomial
expressions.
Therefore numpy.polynomial
is recommended for new coding.
Note
Terminology
The term polynomial module refers to the old API defined in
numpy.lib.polynomial
, which includes the numpy.poly1d
class and
the polynomial functions prefixed with poly accessible from the numpy
namespace (e.g. numpy.polyadd
, numpy.polyval
, numpy.polyfit
, etc.).
The term polynomial package refers to the new API defined in
numpy.polynomial
, which includes the convenience classes for the
different kinds of polynomials (numpy.polynomial.Polynomial
,
numpy.polynomial.Chebyshev
, etc.).
Transitioning from numpy.poly1d
to numpy.polynomial
#
As noted above, the poly1d class
and associated
functions defined in numpy.lib.polynomial
, such as numpy.polyfit
and numpy.poly
, are considered legacy and should not be used in new
code.
Since NumPy version 1.4, the numpy.polynomial
package is preferred for
working with polynomials.
Quick Reference#
The following table highlights some of the main differences between the
legacy polynomial module and the polynomial package for common tasks.
The Polynomial
class is imported for brevity:
from numpy.polynomial import Polynomial
How to… |
Legacy ( |
|
Create a polynomial object from coefficients [1] |
|
|
Create a polynomial object from roots |
|
|
Fit a polynomial of
degree |
|
|
Transition Guide#
There are significant differences between numpy.lib.polynomial
and
numpy.polynomial
.
The most significant difference is the ordering of the coefficients for the
polynomial expressions.
The various routines in numpy.polynomial
all
deal with series whose coefficients go from degree zero upward,
which is the reverse order of the poly1d convention.
The easy way to remember this is that indices
correspond to degree, i.e., coef[i]
is the coefficient of the term of
degree i.
Though the difference in convention may be confusing, it is straightforward to
convert from the legacy polynomial API to the new.
For example, the following demonstrates how you would convert a numpy.poly1d
instance representing the expression \(x^{2} + 2x + 3\) to a
Polynomial
instance representing the same
expression:
>>> p1d = np.poly1d([1, 2, 3])
>>> p = np.polynomial.Polynomial(p1d.coef[::-1])
In addition to the coef
attribute, polynomials from the polynomial
package also have domain
and window
attributes.
These attributes are most relevant when fitting
polynomials to data, though it should be noted that polynomials with
different domain
and window
attributes are not considered equal, and
can’t be mixed in arithmetic:
>>> p1 = np.polynomial.Polynomial([1, 2, 3])
>>> p1
Polynomial([1., 2., 3.], domain=[-1, 1], window=[-1, 1], symbol='x')
>>> p2 = np.polynomial.Polynomial([1, 2, 3], domain=[-2, 2])
>>> p1 == p2
False
>>> p1 + p2
Traceback (most recent call last):
...
TypeError: Domains differ
See the documentation for the
convenience classes for further details on
the domain
and window
attributes.
Another major difference between the legacy polynomial module and the
polynomial package is polynomial fitting. In the old module, fitting was
done via the polyfit
function. In the polynomial package, the
fit
class method is preferred. For
example, consider a simple linear fit to the following data:
In [1]: rng = np.random.default_rng()
In [2]: x = np.arange(10)
In [3]: y = np.arange(10) + rng.standard_normal(10)
With the legacy polynomial module, a linear fit (i.e. polynomial of degree 1)
could be applied to these data with polyfit
:
In [4]: np.polyfit(x, y, deg=1)
Out[4]: array([0.82779319, 1.47439246])
With the new polynomial API, the fit
class method is preferred:
In [5]: p_fitted = np.polynomial.Polynomial.fit(x, y, deg=1)
In [6]: p_fitted
Out[6]: Polynomial([5.1994618 , 3.72506935], domain=[0., 9.], window=[-1., 1.], symbol='x')
Note that the coefficients are given in the scaled domain defined by the
linear mapping between the window
and domain
.
convert
can be used to get the
coefficients in the unscaled data domain.
In [7]: p_fitted.convert()
Out[7]: Polynomial([1.47439246, 0.82779319], domain=[-1., 1.], window=[-1., 1.], symbol='x')
Documentation for the polynomial
Package#
In addition to standard power series polynomials, the polynomial package
provides several additional kinds of polynomials including Chebyshev,
Hermite (two subtypes), Laguerre, and Legendre polynomials.
Each of these has an associated
convenience class available from the
numpy.polynomial
namespace that provides a consistent interface for working
with polynomials regardless of their type.
Documentation pertaining to specific functions defined for each kind of polynomial individually can be found in the corresponding module documentation:
- Power Series (
numpy.polynomial.polynomial
) - Chebyshev Series (
numpy.polynomial.chebyshev
) - Hermite Series, “Physicists” (
numpy.polynomial.hermite
) - HermiteE Series, “Probabilists” (
numpy.polynomial.hermite_e
) - Laguerre Series (
numpy.polynomial.laguerre
) - Legendre Series (
numpy.polynomial.legendre
) - Polyutils