FitResult and FitDiagnostics — Fit Output Types
API reference for FitResult and FitDiagnostics: how to access the fitted model, log-likelihood, AIC, BIC, convergence status, and handle fit errors.
Every Model.fit(data) call in rscopulas returns a FitResult[ModelT] dataclass. The result holds both the fitted model object and a FitDiagnostics instance that lets you evaluate fit quality and check convergence before using the model.
FitResult
FitResult is a generic, frozen dataclass parameterized by the model type.
@dataclass(frozen=True, slots=True)
class FitResult(Generic[ModelT]):
model: ModelT
diagnostics: FitDiagnostics
The fitted copula model. The concrete type matches the class you called fit on—for example, GaussianCopula.fit(data) produces a FitResult[GaussianCopula], so result.model is a GaussianCopula.
FitDiagnostics
FitDiagnostics is a frozen dataclass that reports numerical summaries of the fitting process.
@dataclass(frozen=True, slots=True)
class FitDiagnostics:
loglik: float
aic: float
bic: float
converged: bool
n_iter: int
Log-likelihood evaluated at the fitted parameters. Higher values (closer to zero) indicate a better fit to the data.
Akaike Information Criterion: aic = 2k - 2 * loglik, where k is the number of free parameters. Lower AIC indicates a better balance of fit quality and model complexity.
Bayesian Information Criterion: bic = k * log(n) - 2 * loglik, where n is the number of observations. BIC penalizes complexity more heavily than AIC for large datasets.
True when the optimizer reached its convergence criterion before max_iter. A False value does not mean the result is unusable, but you should inspect the parameter estimates and log-likelihood before relying on the model.
Number of optimizer iterations completed. Useful for diagnosing slow or non-converging fits.
Model comparison with AIC and BIC
When you fit multiple families to the same dataset, use AIC or BIC to select the best model. Both criteria prefer the model with the lower value.
import numpy as np
from rscopulas import GaussianCopula, StudentTCopula, ClaytonCopula
rng = np.random.default_rng(0)
data = rng.uniform(0.01, 0.99, size=(500, 2))
results = {
"gaussian": GaussianCopula.fit(data),
"student_t": StudentTCopula.fit(data),
"clayton": ClaytonCopula.fit(data),
}
best = min(results, key=lambda name: results[name].diagnostics.aic)
print("Best family by AIC:", best)
for name, result in results.items():
d = result.diagnostics
print(f"{name}: loglik={d.loglik:.2f}, AIC={d.aic:.2f}, BIC={d.bic:.2f}")
Accessing all fields
import numpy as np
from rscopulas import GaussianCopula
rng = np.random.default_rng(42)
data = rng.uniform(0.01, 0.99, size=(400, 3))
result = GaussianCopula.fit(data)
# Fitted model
model = result.model
print("correlation:\n", model.correlation)
# Diagnostics
d = result.diagnostics
print("log-likelihood:", d.loglik)
print("AIC:", d.aic)
print("BIC:", d.bic)
print("converged:", d.converged)
print("iterations:", d.n_iter)
# Downstream use
log_densities = model.log_pdf(data)
new_samples = model.sample(100, seed=0)
Error handling
Fitting can raise several exceptions. You should always catch at least InvalidInputError and ModelFitError in production code.
import numpy as np
from rscopulas import GaussianCopula, InvalidInputError, ModelFitError
data = np.array([[0.1, 0.2], [0.5, 0.6], [0.9, 0.8]], dtype=np.float64)
try:
result = GaussianCopula.fit(data)
if not result.diagnostics.converged:
print(f"Warning: did not converge after {result.diagnostics.n_iter} iterations")
print("AIC:", result.diagnostics.aic)
except InvalidInputError as e:
print("Invalid input:", e)
except ModelFitError as e:
print("Fit failed:", e)
Error types
| Exception | When raised |
|---|---|
RscopulasError | Base class for all library exceptions. Catch this to handle any rscopulas error. |
InvalidInputError | Input data fails validation: wrong dtype, wrong shape, values outside (0, 1), or an invalid parameter value. |
ModelFitError | The optimization algorithm fails to find a valid solution, e.g. a singular correlation matrix. |
NumericalError | A numerical operation (log, inversion, etc.) produces an invalid result such as NaN or Inf. |
BackendError | An internal error in the Rust backend that does not fall into the categories above. |
InternalError | An internal Rust panic was caught at the Python boundary. This indicates a bug in rscopulas and should be reported upstream. |