pub fn boxcox_capability(
data: &[f64],
usl: Option<f64>,
lsl: Option<f64>,
lambda_range: (f64, f64),
) -> Result<NonNormalCapabilityResult, NonNormalCapabilityError>Expand description
Compute process capability indices for non-normal data via Box-Cox transformation.
The data are first transformed to approximate normality using the optimal
Box-Cox parameter λ, estimated via maximum likelihood over lambda_range
(usually DEFAULT_LAMBDA_RANGE). Specification limits are transformed
using the same λ. The long-term capability indices (Pp, Ppk, Ppu, Ppl)
are then computed on the transformed scale. The short-term indices
(Cp, Cpk, Cpu, Cpl) are not reported — see
NonNormalCapabilityResult::indices for why.
Specification limits are optional: without either, λ and
NonNormalCapabilityResult::lambda_at_bound are still estimated and
indices is None — the “does a transform achieve normality” half of a
non-normal capability workflow comes before the limits are known.
§Arguments
data— Process observations. All values must be strictly positive.usl— Upper specification limit (optional). Must be positive if provided.lsl— Lower specification limit (optional). Must be positive if provided.lambda_range—(min, max)λ search range, finite withmin < max.
§Errors
Returns NonNormalCapabilityError if:
- Fewer than 4 data points are provided.
- Any data value is ≤ 0 (Box-Cox requires strictly positive data).
lambda_rangeis not finite withmin < max.- A specification limit is ≤ 0 (cannot be Box-Cox transformed).
- Capability computation fails (e.g., zero variance in transformed data).
§Examples
use u_analytics::capability::{boxcox_capability, DEFAULT_LAMBDA_RANGE};
// Right-skewed data
let data: Vec<f64> = (1..=20).map(|i| (i as f64 * 0.3_f64).exp()).collect();
let result = boxcox_capability(&data, Some(100.0), Some(1.0), DEFAULT_LAMBDA_RANGE).unwrap();
assert!(!result.lambda_at_bound);
assert!(result.indices.expect("limits given").ppk.is_some());
// No limits yet: the transform alone.
let lambda_only = boxcox_capability(&data, None, None, DEFAULT_LAMBDA_RANGE).unwrap();
assert_eq!(lambda_only.lambda, result.lambda);
assert!(lambda_only.indices.is_none());