numpy polyfit RankWarning: Polyfit may be poorly conditioned (tested)

RankWarning: Polyfit may be poorly conditioned means the fit is rank-deficient: the degree is too high for the number of points, or large x values (like years) make the matrix numerically singular. Center/scale x (or use Polynomial.fit), lower the degree, and drop NaN values first, which otherwise give all-NaN coefficients silently.

1. The warning and the errors, reproduced

Run with python b1.py (numpy 2.5.4, Python 3.13.5):

import numpy as np

print("numpy", np.__version__)
x = np.arange(10, dtype=float)
y = x ** 2

# 1. degree higher than the data supports
c = np.polyfit(x[:3], y[:3], deg=5)
print("deg 5 on 3 points:", np.round(c, 3))

# 2. huge x values (years) with a high degree
years = np.arange(2000, 2021, dtype=float)
vals = np.sin(years)
c = np.polyfit(years, vals, deg=8)

# 3. NaN in the data
y_nan = y.copy(); y_nan[3] = np.nan
try:
    print("NaN in y ->", np.polyfit(x, y_nan, 1))
except np.linalg.LinAlgError as e:
    print("NaN -> LinAlgError:", e)

# 4. too few points / mismatched lengths
for args in [(x[:0], y[:0]), (x, y[:5])]:
    try:
        np.polyfit(*args, 1)
    except (TypeError, ValueError) as e:
        print(type(e).__name__ + ":", e)

Output:

numpy 2.5.4
/tmp/pf403/b1.py:8: RankWarning: Polyfit may be poorly conditioned
  c = np.polyfit(x[:3], y[:3], deg=5)
deg 5 on 3 points: [ 0.016  0.036  0.089  0.236  0.623 -0.   ]
/tmp/pf403/b1.py:14: RankWarning: Polyfit may be poorly conditioned
  c = np.polyfit(years, vals, deg=8)
NaN in y -> [nan nan]
TypeError: expected non-empty vector for x
TypeError: expected x and y to have same length

2. Fixes that worked

import warnings
import numpy as np
from numpy.polynomial import Polynomial

years = np.arange(2000, 2021, dtype=float)
vals = np.sin(years)

# full=True returns the rank instead of only warning
c, res, rank, sv, rcond = np.polyfit(years, vals, 8, full=True)
print("full=True: rank", rank, "of", 8 + 1)

# shift/scale x first
c = np.polyfit(years - 2000, vals, 8)
print("years - 2000: fitted, no warning")

# Polynomial.fit maps x to [-1, 1] internally
p = Polynomial.fit(years, vals, 8)
print("Polynomial.fit: no warning, domain", p.domain)

# catch it as an exception
try:
    np.RankWarning
except AttributeError as e:
    print("AttributeError:", str(e)[:80])
with warnings.catch_warnings():
    warnings.simplefilter("error", np.exceptions.RankWarning)
    try:
        np.polyfit(years, vals, 8)
    except np.exceptions.RankWarning as e:
        print("raised:", e)

# NaN: drop missing points first
x = np.arange(10, dtype=float); y = x ** 2; y[3] = np.nan
ok = ~np.isnan(y)
print("after dropping NaN:", np.round(np.polyfit(x[ok], y[ok], 2), 6))

Output:

full=True: rank 6 of 9
years - 2000: fitted, no warning
Polynomial.fit: no warning, domain [2000. 2020.]
AttributeError: module 'numpy' has no attribute 'RankWarning'
raised: Polyfit may be poorly conditioned
after dropping NaN: [1. 0. 0.]

If the warning remains after scaling, lower the degree: a high-degree polynomial through noisy data rarely means anything outside the fitted points.

Related: numpy LinAlgError: Singular matrix · numpy errstate · numpy 2 breaking changes.

Frequently asked questions

What does RankWarning: Polyfit may be poorly conditioned mean?

The least-squares matrix is rank-deficient: the polynomial degree is too high for the data or x values are so large that powers of x swamp the other columns. Coefficients are returned but not reliable.

How do I fix a poorly conditioned polyfit?

Center or scale x (e.g. years - 2000), or use numpy.polynomial.Polynomial.fit which scales the domain to [-1, 1]; lower the degree if the warning remains.

Why does np.polyfit return nan?

A NaN in x or y makes all coefficients NaN without a warning. Remove missing points with a mask such as ~np.isnan(y) before fitting.

Where is np.RankWarning in numpy 2?

It was removed from the main namespace; use np.exceptions.RankWarning.

Written with AI assistance. Measured on 2026-10-23 with numpy 2.5.4 and Python 3.13.5 on Linux. Each script was run verbatim and the output pasted unedited. PlainTables is our extension; numpy is free.