Skip to content

Parameter Importance

When you have a model f(p1,p2,,pn)f(p_1, p_2, \ldots, p_n) that takes a parameter vector and returns a scalar, “parameter importance” is the question which pip_i matters most for the output. Numra answers this with compute_sensitivities, a one-shot local sensitivity routine built on central finite differences.

The basic form takes a closure, a nominal parameter vector, optional parameter names, and an optional finite-difference step size:

use numra::compute_sensitivities;
// A model: output = a^2 · sin(b) + c
let f = |p: &[f64]| p[0] * p[0] * p[1].sin() + p[2];
let params = [3.0, 1.5, 10.0];
let names = ["a", "b", "c"];
let result = compute_sensitivities(f, &params, &names, None);
println!("Output: {:.4}", result.output);
for s in &result.sensitivities {
println!(
"{}: coefficient = {:.4}, normalized = {:.4}",
s.name, s.coefficient, s.normalized,
);
}

Each parameter contributes one row to result.sensitivities.

Each parameter gets two metrics:

MetricFormulaInterpretation
Coefficientf/pi\partial f / \partial p_iAbsolute rate of change — has units.
Normalized(pi/f)f/pi(p_i / f) \cdot \partial f / \partial p_iDimensionless elasticity. A value of 0.50.5 means a 1% change in pip_i produces approximately a 0.5% change in the output.

Use the coefficient when you care about the physical scale of sensitivity (e.g. “how many degrees Celsius does the output shift per unit change in this rate constant?”). Use the normalized sensitivity when you want to rank parameters whose values span very different magnitudes — say, a rate constant of 10310^{-3} alongside a temperature of 300300.

A common follow-up is “which is the most influential parameter?”:

let most = result.most_sensitive().unwrap();
println!(
"Most influential: {} (normalized = {:.4})",
most.name, most.normalized,
);

most_sensitive ranks by the absolute value of normalized. For problems where parameters share a common physical unit, you may prefer to rank by coefficient.abs() instead — iterate manually and sort.

Uncertainty propagation from sensitivities

Section titled “Uncertainty propagation from sensitivities”

If you also know the variances of the input parameters, the local linearisation lets you estimate the output variance directly:

σf2    i(fpi) ⁣2σpi2\sigma_f^2 \;\approx\; \sum_i \left(\frac{\partial f}{\partial p_i}\right)^{\!2} \sigma_{p_i}^2

assuming the parameters are independent and the function is well approximated as linear in the parameter range of interest. Numra exposes this as a one-line helper:

let param_variances = [0.1, 0.05, 1.0]; // Var(a), Var(b), Var(c)
let output_variance = result.propagate_uncertainty(&param_variances);
println!("Predicted output std: {:.4}", output_variance.sqrt());

For correlated parameters, larger uncertainties, or strongly nonlinear ff, this first-order estimate can be very wrong — fall back to Monte Carlo or full uncertainty propagation via Uncertain<S>.

The default step size is h=107(1+pi)h = 10^{-7} \cdot (1 + |p_i|), a relative step that adapts to each parameter’s magnitude. Override the step size when needed:

let result = compute_sensitivities(f, &params, &names, Some(1e-5));
DirectionEffect
Smaller hhLower truncation error; more susceptible to floating-point cancellation.
Larger hhMore cancellation-resistant; truncation error grows quadratically (central FD).

The default 107(1+p)10^{-7} \cdot (1 + \lvert p \rvert) is a good compromise for most well-conditioned problems and gives roughly 1010 correct digits when the function is smooth and not pathologically scaled.

compute_sensitivities is the right tool when:

  • The model is a scalar function of parameters, not a trajectory.
  • You want a quick local picture at one nominal parameter point.
  • The function is reasonably smooth and you can afford 2n+12n + 1 evaluations (central FD plus baseline).

If your model is an ODE/DAE and you want y(t)/p\partial y(t) / \partial p at every output time along the trajectory, you want the forward sensitivity primitive on the Sensitivity Analysis page instead. The augmented-system approach there integrates state and sensitivity together — one solver call, single source of truth on tolerances and step control, and analytical Jacobians available where they matter.