Degradation Analysis

Degradation Analysis Fitter

class surpyval.degradation.degradation_analysis.DegradationAnalysis_

Bases: object

Pseudo-failure-time degradation analysis.

Fits a degradation path model to each unit’s measurements, extrapolates each fitted path to the failure threshold to obtain per-unit pseudo failure times, and fits a lifetime distribution to those times. Units whose fitted path never reaches the threshold at a positive finite time are right censored at their last observed time (with a warning).

Examples

>>> import numpy as np
>>> from surpyval.degradation import DegradationAnalysis
>>> # 4 units measured every 100 hours; degradation grows linearly
>>> # at a different rate per unit; failure is defined at level 150.
>>> x = np.tile(np.arange(100, 1100, 100), 4)
>>> slopes = np.repeat([0.31, 0.28, 0.44, 0.37], 10)
>>> i = np.repeat([1, 2, 3, 4], 10)
>>> y = 10 + slopes * x
>>> model = DegradationAnalysis.fit(x, y, i, threshold=150)
>>> print(model)
Degradation Analysis SurPyval Model
===================================
Path Model          : Linear
Threshold           : 150.0
Number of Units     : 4
Censored Units      : 0
Life Distribution   : Weibull
Parameters          :
     alpha: 441.4780882117898
      beta: 6.987078993008337
>>> model.pseudo_failure_times
array([451.61290323, 500.        , 318.18181818, 378.37837838])
fit(x: ArrayLike, y: ArrayLike, i: ArrayLike, threshold: float, path: str | surpyval.degradation.path_models.PathModel = 'linear', distribution=<surpyval.univariate.parametric.distributions.weibull.Weibull_ object>, how: str = 'MLE', population_method: str = 'moments') DegradationModel

Fit a degradation analysis model.

Parameters
  • x (array like) – Times at which the degradation measurements were taken.

  • y (array like) – The degradation measurements.

  • i (array like) – The unit each measurement belongs to. Must have the same length as x and y.

  • threshold (float) – The degradation level at which a unit is defined to have failed.

  • path (str or PathModel, optional) – The degradation path model fitted to each unit: one of "linear" (default), "quadratic", "exponential", "offset-exponential", "power", "logarithmic", "lloyd-lipow", "gompertz", "michaelis-menten", a PathModel instance, or "best" to fit every registered model to all units and select the one with the smallest AICc (the per-candidate scores are exposed as path_selection on the returned model; candidates that cannot be fitted to every unit are excluded).

  • distribution (ParametricFitter, optional) – The lifetime distribution fitted to the pseudo failure times. Defaults to Weibull.

  • how (str, optional) – The method used to fit the lifetime distribution (passed to distribution.fit). Defaults to "MLE".

  • population_method (str, optional) – How the population path-parameter distribution (path_param_mean, path_param_cov, measurement_var) is estimated. "moments" (default) uses the two-stage noise-corrected sample moments; "reml" maximises the restricted marginal likelihood of the linear mixed model, which cannot go rank-deficient and is preferable with few units. REML is available for path models that are linear in their parameters (linear, quadratic, logarithmic, lloyd-lipow) and requires measurement noise (some unit with more measurements than path parameters).

Returns

The fitted degradation model, with the per-unit paths, pseudo failure times, and the fitted life model.

Return type

DegradationModel

fit_from_df(df: DataFrame, x: str = 'x', y: str = 'y', i: str = 'i', **fit_kwargs) DegradationModel

Fit a degradation analysis model from a DataFrame.

Parameters
  • df (DataFrame) – DataFrame with the degradation data.

  • x (str, optional) – Column of the measurement times. Defaults to "x".

  • y (str, optional) – Column of the degradation measurements. Defaults to "y".

  • i (str, optional) – Column of the unit identifiers. Defaults to "i".

  • **fit_kwargs – Remaining arguments (threshold, path, distribution, how) passed to fit().

Returns

The fitted degradation model.

Return type

DegradationModel

Degradation Model

class surpyval.degradation.degradation_analysis.DegradationModel(x, y, i, units, threshold, path_model, path_params, pseudo_failure_times, c, life_model, measurement_var, path_param_mean, path_param_cov, path_param_sample_cov, population_method, path_selection=None)

Bases: object

A fitted degradation analysis model.

This is the model object returned by DegradationAnalysis.fit(). It holds the per-unit fitted degradation paths, the pseudo failure times extrapolated from them, and the lifetime distribution fitted to those pseudo failure times. The usual lifetime functions (sf, ff, df, hf, Hf, qf, mean, random) are forwarded to the fitted life model, and the failure time of a new, partially observed unit can be estimated from its trajectory with predict_failure_time() / predict_remaining_life().

Parameters
  • x (ndarray) – The degradation data: measurement times, measurements, and the unit each measurement belongs to.

  • y (ndarray) – The degradation data: measurement times, measurements, and the unit each measurement belongs to.

  • i (ndarray) – The degradation data: measurement times, measurements, and the unit each measurement belongs to.

  • units (ndarray) – The distinct unit identifiers.

  • threshold (float) – The degradation level at which a unit is considered failed.

  • path_model (PathModel) – The degradation path model fitted to each unit.

  • path_params (ndarray) – Per-unit fitted path parameters, one row per entry of units.

  • pseudo_failure_times (ndarray) – Per-unit pseudo failure time: the extrapolated threshold crossing time, or the unit’s last observed time for censored units.

  • c (ndarray) – Per-unit censor flags: 0 where the fitted path crosses the threshold, 1 (right censored) where it never does.

  • life_model (Parametric) – The lifetime distribution fitted to the pseudo failure times.

  • measurement_var (float) – Pooled estimate of the measurement-error variance around the per-unit paths (the per-unit residual sums of squares over the total residual degrees of freedom). Zero when every unit has exactly as many measurements as path parameters.

  • path_param_mean (ndarray) – Mean of the per-unit fitted path parameters: the estimated population mean path.

  • path_param_cov (ndarray) – Noise-corrected estimate of the between-unit covariance of the true path parameters (Lu-Meeker two-stage): the sample covariance of the per-unit estimates minus the average least-squares estimation covariance, projected onto the positive semi-definite cone.

  • path_param_sample_cov (ndarray) – The raw (uncorrected) sample covariance of the per-unit fitted path parameters. This overstates the between-unit variability because each per-unit estimate also carries least-squares estimation noise.

  • population_method (str) – How the population estimates (measurement_var, path_param_mean, path_param_cov) were obtained: "moments" (two-stage correction) or "reml".

  • path_selection (dict or None) – When fitted with path="best", the AICc score of every candidate path model (nan for candidates that could not be fitted to every unit); None otherwise. The fitted path_model is the candidate with the smallest score.

Hf(x: ArrayLike) NDArray

Cumulative hazard of the fitted life model.

df(x: ArrayLike) NDArray

Density of the fitted life model.

ff(x: ArrayLike) NDArray

CDF of the fitted life model.

hf(x: ArrayLike) NDArray

Hazard rate of the fitted life model.

mean() float

Mean of the fitted life model.

path(x: ArrayLike, unit) NDArray

Evaluate the fitted degradation path of unit at x.

plot(ax=None)

Plot the degradation data, the fitted per-unit paths (extended to each unit’s pseudo failure time), and the failure threshold.

Parameters

ax (matplotlib axes, optional) – An axes object to draw the plot on. Creates a new one if not provided.

Returns

An axes object with the plot.

Return type

matplotlib axes

predict_failure_time(x: ArrayLike, y: ArrayLike) float

Estimate the failure time of a new unit from its (partial) degradation trajectory.

Fits this model’s path model to the new unit’s measurements and extrapolates the fitted path to this model’s failure threshold, exactly as was done for each unit during fitting.

Parameters
  • x (array like) – Times at which the new unit’s measurements were taken.

  • y (array like) – The new unit’s degradation measurements.

Returns

The time at which the new unit’s fitted path reaches the threshold. This can be smaller than the last observed time if the trajectory has already crossed the threshold. Returns nan (with a warning) if the fitted path never reaches the threshold.

Return type

float

predict_remaining_life(x: ArrayLike, y: ArrayLike) float

Estimate the remaining life of a new unit from its (partial) degradation trajectory.

This is predict_failure_time() minus the new unit’s last observed time. A negative value means the fitted path crossed the threshold before the last observation (the unit is predicted to have already failed); nan (with a warning) means the fitted path never reaches the threshold.

predict_rul(x: ArrayLike, y: ArrayLike, alpha_ci: float = 0.05, n_samples: int = 10000, random_state=None) RULPrediction

Bayesian remaining-useful-life prediction for a new unit.

The population distribution of path parameters estimated at fit time (path_param_mean, path_param_cov) is used as a prior, the new unit’s measurements as the likelihood (with the pooled measurement_var as the noise variance), and the Gaussian posterior of the unit’s path parameters is pushed through the threshold crossing by Monte Carlo. The posterior is exact (conjugate) for path models that are linear in their parameters, and an iterated-linearisation (Laplace) approximation otherwise.

Compared to predict_failure_time(), this shrinks short or noisy trajectories toward the population instead of trusting the raw extrapolation, works from a single measurement, and returns credible intervals. With many measurements the posterior concentrates on the least-squares fit and the two agree.

Parameters
  • x (array like) – Times at which the new unit’s measurements were taken. One or more measurements are required.

  • y (array like) – The new unit’s degradation measurements.

  • alpha_ci (float, optional) – Significance level for the equal-tailed credible intervals. Defaults to 0.05 (95% intervals).

  • n_samples (int, optional) – Number of Monte Carlo posterior samples. Defaults to 10,000.

  • random_state (optional) – Seed passed to numpy.random.default_rng for reproducible sampling.

Returns

Posterior medians, credible intervals, failure probabilities, and the parameter posterior.

Return type

RULPrediction

qf(p: ArrayLike) NDArray

Quantile function of the fitted life model.

random(size: int) NDArray

Random pseudo failure times from the fitted life model.

sf(x: ArrayLike) NDArray

Survival function of the fitted life model.

class surpyval.degradation.degradation_analysis.RULPrediction(failure_time: float, failure_time_interval: tuple[float, float], rul: float, rul_interval: tuple[float, float], prob_failed: float, prob_never_fails: float, posterior_mean: NDArray, posterior_cov: NDArray, alpha_ci: float, samples: NDArray)

Bases: object

Posterior failure-time / remaining-useful-life prediction for a new unit, returned by DegradationModel.predict_rul().

All summaries come from Monte Carlo samples of the new unit’s path parameters drawn from their Gaussian posterior and pushed through the path model’s threshold crossing. Samples whose path never reaches the threshold contribute inf failure times, so the median and interval endpoints can be inf when much of the posterior mass never fails.

Parameters
  • failure_time (float) – Posterior median of the unit’s failure time (measured from the unit’s time zero, like the fitted life model).

  • failure_time_interval (tuple of float) – Equal-tailed 1 - alpha_ci credible interval for the failure time.

  • rul (float) – Posterior median remaining useful life: failure time minus the unit’s last observed time. Negative means the unit has most likely already crossed the threshold.

  • rul_interval (tuple of float) – Equal-tailed 1 - alpha_ci credible interval for the remaining useful life.

  • prob_failed (float) – Posterior probability that the unit’s path has already crossed the threshold (failure time at or before its last observed time).

  • prob_never_fails (float) – Posterior probability that the unit’s path never reaches the threshold.

  • posterior_mean (ndarray) – The Gaussian posterior of the unit’s path parameters.

  • posterior_cov (ndarray) – The Gaussian posterior of the unit’s path parameters.

  • alpha_ci (float) – The interval significance level used.

  • samples (ndarray) – The Monte Carlo failure-time samples (inf where the sampled path never reaches the threshold).

Path Models

class surpyval.degradation.path_models.PathModel

Bases: ABC

Base class for degradation path models.

A path model is a deterministic function of time with a small number of parameters that is fitted, per unit, to that unit’s degradation measurements. Subclass this (implementing path, inv_path, fit and the name/param_names attributes) to use a custom degradation path with DegradationAnalysis.

check_data(x: NDArray, y: NDArray) None

Raise ValueError if the data is outside the model domain.

fit(x: ArrayLike, y: ArrayLike) NDArray

Fit the path parameters to one unit’s measurements by (nonlinear) least squares.

abstract inv_path(y: ArrayLike, *params: float) NDArray

Time at which the path reaches level y.

Returns a non-finite value (nan or inf) or a non-positive value when the path never reaches y at a positive finite time.

jacobian(x: ArrayLike, *params: float) NDArray

Partial derivatives of path with respect to the parameters, evaluated at time(s) x: a (len(x), n_params) matrix.

Used to estimate the least-squares estimation covariance of per-unit fitted parameters. The base implementation uses central finite differences; the built-in models override it with the analytic derivatives.

linear_in_parameters: bool = False

True when path is linear in its parameters, i.e. path(x, *theta) == jacobian(x) @ theta with a Jacobian that does not depend on theta. Enables exact conjugate posterior updates and REML population estimation.

abstract path(x: ArrayLike, *params: float) NDArray

Evaluate the degradation path at time(s) x.

class surpyval.degradation.path_models.LinearPath_

Bases: PathModel

Linear degradation path: y = a + b * x.

check_data(x: NDArray, y: NDArray) None

Raise ValueError if the data is outside the model domain.

fit(x, y)

Fit the path parameters to one unit’s measurements by (nonlinear) least squares.

inv_path(y, *params)

Time at which the path reaches level y.

Returns a non-finite value (nan or inf) or a non-positive value when the path never reaches y at a positive finite time.

jacobian(x, *params)

Partial derivatives of path with respect to the parameters, evaluated at time(s) x: a (len(x), n_params) matrix.

Used to estimate the least-squares estimation covariance of per-unit fitted parameters. The base implementation uses central finite differences; the built-in models override it with the analytic derivatives.

linear_in_parameters: bool = True

True when path is linear in its parameters, i.e. path(x, *theta) == jacobian(x) @ theta with a Jacobian that does not depend on theta. Enables exact conjugate posterior updates and REML population estimation.

path(x, *params)

Evaluate the degradation path at time(s) x.

class surpyval.degradation.path_models.QuadraticPath_

Bases: PathModel

Quadratic degradation path: y = a + b * x + c * x**2.

check_data(x: NDArray, y: NDArray) None

Raise ValueError if the data is outside the model domain.

fit(x, y)

Fit the path parameters to one unit’s measurements by (nonlinear) least squares.

inv_path(y, *params)

First positive time at which the parabola reaches y.

jacobian(x, *params)

Partial derivatives of path with respect to the parameters, evaluated at time(s) x: a (len(x), n_params) matrix.

Used to estimate the least-squares estimation covariance of per-unit fitted parameters. The base implementation uses central finite differences; the built-in models override it with the analytic derivatives.

linear_in_parameters: bool = True

True when path is linear in its parameters, i.e. path(x, *theta) == jacobian(x) @ theta with a Jacobian that does not depend on theta. Enables exact conjugate posterior updates and REML population estimation.

path(x, *params)

Evaluate the degradation path at time(s) x.

class surpyval.degradation.path_models.ExponentialPath_

Bases: PathModel

Exponential degradation path: y = a * exp(b * x).

check_data(x, y)

Raise ValueError if the data is outside the model domain.

fit(x: ArrayLike, y: ArrayLike) NDArray

Fit the path parameters to one unit’s measurements by (nonlinear) least squares.

inv_path(y, *params)

Time at which the path reaches level y.

Returns a non-finite value (nan or inf) or a non-positive value when the path never reaches y at a positive finite time.

jacobian(x, *params)

Partial derivatives of path with respect to the parameters, evaluated at time(s) x: a (len(x), n_params) matrix.

Used to estimate the least-squares estimation covariance of per-unit fitted parameters. The base implementation uses central finite differences; the built-in models override it with the analytic derivatives.

linear_in_parameters: bool = False

True when path is linear in its parameters, i.e. path(x, *theta) == jacobian(x) @ theta with a Jacobian that does not depend on theta. Enables exact conjugate posterior updates and REML population estimation.

path(x, *params)

Evaluate the degradation path at time(s) x.

class surpyval.degradation.path_models.OffsetExponentialPath_

Bases: PathModel

Offset exponential degradation path: y = a + b * exp(c * x).

Covers exponential growth or decay toward/away from the asymptote a; with a = 0 it reduces to the exponential path.

check_data(x: NDArray, y: NDArray) None

Raise ValueError if the data is outside the model domain.

fit(x: ArrayLike, y: ArrayLike) NDArray

Fit the path parameters to one unit’s measurements by (nonlinear) least squares.

inv_path(y, *params)

Time at which the path reaches level y.

Returns a non-finite value (nan or inf) or a non-positive value when the path never reaches y at a positive finite time.

jacobian(x, *params)

Partial derivatives of path with respect to the parameters, evaluated at time(s) x: a (len(x), n_params) matrix.

Used to estimate the least-squares estimation covariance of per-unit fitted parameters. The base implementation uses central finite differences; the built-in models override it with the analytic derivatives.

linear_in_parameters: bool = False

True when path is linear in its parameters, i.e. path(x, *theta) == jacobian(x) @ theta with a Jacobian that does not depend on theta. Enables exact conjugate posterior updates and REML population estimation.

path(x, *params)

Evaluate the degradation path at time(s) x.

class surpyval.degradation.path_models.PowerPath_

Bases: PathModel

Power degradation path: y = a * x**b.

check_data(x, y)

Raise ValueError if the data is outside the model domain.

fit(x: ArrayLike, y: ArrayLike) NDArray

Fit the path parameters to one unit’s measurements by (nonlinear) least squares.

inv_path(y, *params)

Time at which the path reaches level y.

Returns a non-finite value (nan or inf) or a non-positive value when the path never reaches y at a positive finite time.

jacobian(x, *params)

Partial derivatives of path with respect to the parameters, evaluated at time(s) x: a (len(x), n_params) matrix.

Used to estimate the least-squares estimation covariance of per-unit fitted parameters. The base implementation uses central finite differences; the built-in models override it with the analytic derivatives.

linear_in_parameters: bool = False

True when path is linear in its parameters, i.e. path(x, *theta) == jacobian(x) @ theta with a Jacobian that does not depend on theta. Enables exact conjugate posterior updates and REML population estimation.

path(x, *params)

Evaluate the degradation path at time(s) x.

class surpyval.degradation.path_models.LogarithmicPath_

Bases: PathModel

Logarithmic degradation path: y = a + b * ln(x).

check_data(x, y)

Raise ValueError if the data is outside the model domain.

fit(x, y)

Fit the path parameters to one unit’s measurements by (nonlinear) least squares.

inv_path(y, *params)

Time at which the path reaches level y.

Returns a non-finite value (nan or inf) or a non-positive value when the path never reaches y at a positive finite time.

jacobian(x, *params)

Partial derivatives of path with respect to the parameters, evaluated at time(s) x: a (len(x), n_params) matrix.

Used to estimate the least-squares estimation covariance of per-unit fitted parameters. The base implementation uses central finite differences; the built-in models override it with the analytic derivatives.

linear_in_parameters: bool = True

True when path is linear in its parameters, i.e. path(x, *theta) == jacobian(x) @ theta with a Jacobian that does not depend on theta. Enables exact conjugate posterior updates and REML population estimation.

path(x, *params)

Evaluate the degradation path at time(s) x.

class surpyval.degradation.path_models.LloydLipowPath_

Bases: PathModel

Lloyd-Lipow degradation path: y = a - b / x.

check_data(x, y)

Raise ValueError if the data is outside the model domain.

fit(x, y)

Fit the path parameters to one unit’s measurements by (nonlinear) least squares.

inv_path(y, *params)

Time at which the path reaches level y.

Returns a non-finite value (nan or inf) or a non-positive value when the path never reaches y at a positive finite time.

jacobian(x, *params)

Partial derivatives of path with respect to the parameters, evaluated at time(s) x: a (len(x), n_params) matrix.

Used to estimate the least-squares estimation covariance of per-unit fitted parameters. The base implementation uses central finite differences; the built-in models override it with the analytic derivatives.

linear_in_parameters: bool = True

True when path is linear in its parameters, i.e. path(x, *theta) == jacobian(x) @ theta with a Jacobian that does not depend on theta. Enables exact conjugate posterior updates and REML population estimation.

path(x, *params)

Evaluate the degradation path at time(s) x.

class surpyval.degradation.path_models.GompertzPath_

Bases: PathModel

Gompertz degradation path: y = a * exp(-b * exp(-c * x)).

An S-shaped path approaching the asymptote a.

check_data(x, y)

Raise ValueError if the data is outside the model domain.

fit(x: ArrayLike, y: ArrayLike) NDArray

Fit the path parameters to one unit’s measurements by (nonlinear) least squares.

inv_path(y, *params)

Time at which the path reaches level y.

Returns a non-finite value (nan or inf) or a non-positive value when the path never reaches y at a positive finite time.

jacobian(x, *params)

Partial derivatives of path with respect to the parameters, evaluated at time(s) x: a (len(x), n_params) matrix.

Used to estimate the least-squares estimation covariance of per-unit fitted parameters. The base implementation uses central finite differences; the built-in models override it with the analytic derivatives.

linear_in_parameters: bool = False

True when path is linear in its parameters, i.e. path(x, *theta) == jacobian(x) @ theta with a Jacobian that does not depend on theta. Enables exact conjugate posterior updates and REML population estimation.

path(x, *params)

Evaluate the degradation path at time(s) x.

class surpyval.degradation.path_models.MichaelisMentenPath_

Bases: PathModel

Michaelis-Menten degradation path: y = a * x / (b + x).

A saturating path rising from zero toward the asymptote a, reaching half of it at x = b.

check_data(x, y)

Raise ValueError if the data is outside the model domain.

fit(x: ArrayLike, y: ArrayLike) NDArray

Fit the path parameters to one unit’s measurements by (nonlinear) least squares.

inv_path(y, *params)

Time at which the path reaches level y.

Returns a non-finite value (nan or inf) or a non-positive value when the path never reaches y at a positive finite time.

jacobian(x, *params)

Partial derivatives of path with respect to the parameters, evaluated at time(s) x: a (len(x), n_params) matrix.

Used to estimate the least-squares estimation covariance of per-unit fitted parameters. The base implementation uses central finite differences; the built-in models override it with the analytic derivatives.

linear_in_parameters: bool = False

True when path is linear in its parameters, i.e. path(x, *theta) == jacobian(x) @ theta with a Jacobian that does not depend on theta. Enables exact conjugate posterior updates and REML population estimation.

path(x, *params)

Evaluate the degradation path at time(s) x.

surpyval.degradation.path_models.get_path_model(path: str | surpyval.degradation.path_models.PathModel) PathModel

Resolve path to a PathModel instance.

Accepts a PathModel instance (returned unchanged) or one of the registered names in PATH_MODELS (case-insensitive): "linear", "quadratic", "exponential", "offset-exponential", "power", "logarithmic", "lloyd-lipow", "gompertz", "michaelis-menten". ("best" — automatic selection — is handled by DegradationAnalysis.fit, not here.)