pub fn estimate_lambda(
y: &[f64],
lambda_min: f64,
lambda_max: f64,
) -> Result<LambdaEstimate, TransformError>Expand description
Estimate the optimal Box-Cox λ via maximum likelihood.
Maximises the profile log-likelihood:
ℓ(λ) = -(n/2)·ln(Var_population(y(λ))) + (λ-1)·Σ ln(yᵢ)using a golden-section search over [lambda_min, lambda_max] with up
to 100 iterations (terminating early when the bracket width < 1e-6).
The result says whether the maximum was found on an end of the range
(LambdaEstimate::at_bound): a λ of lambda_max because the likelihood
peaks there is indistinguishable by value from one where the likelihood
keeps rising past it, and only the latter means the range cut the search
short.
§Errors
TransformError::InvalidLambdaRange—lambda_min >= lambda_max, or either bound is not finiteTransformError::InsufficientData— fewer than 2 data pointsTransformError::NonPositiveData— any element ≤ 0TransformError::NonFiniteData— any element is NaN or infinite
§Examples
use u_numflow::transforms::estimate_lambda;
// Exponential data is well-linearised by log (λ ≈ 0).
let y: Vec<f64> = (1..=30).map(|i| (i as f64 * 0.2_f64).exp()).collect();
let est = estimate_lambda(&y, -2.0, 2.0).unwrap();
assert!(est.lambda.abs() < 0.3, "expected lambda near 0, got {}", est.lambda);
assert!(!est.at_bound);