First-order Sobol sensitivity indices from the data you already have. sobolnp estimates how much of the variance of an output \(Y\) is explained by each input \(X_i\),
\[ S_i = \frac{\operatorname{Var}\left( \mathbb{E}[Y \mid X_i] \right)}{\operatorname{Var}(Y)}, \]
using only a sample of \((X, Y)\). It does not need to run the model again and does not need to know its formula.
Most Sobol estimators are built for a computer model that you can call at will. They evaluate it on a specially designed set of points, usually many times. That is a problem when each model run is expensive, when the model is a black box you can no longer run, or when all you have is observational data.
| Monte Carlo / pick-freeze (Sobol, Saltelli, Jansen, …) |
FAST | Metamodel (splines, kriging) |
sobolnp | |
|---|---|---|---|---|
| Needs to run the model | yes | yes | to train it | no |
| Needs a designed sample | yes (frozen copies) | yes (frequency design) | yes (training design) | no, any i.i.d. sample |
| Model runs typically needed | \(10^4\)–\(10^5\) | \(10^3\)–\(10^4\) | \(10^2\)–\(10^3\) + fitting | the sample you have (\(10^2\)–\(10^3\)) |
| Finite-sample bias correction | — | — | depends on the metamodel | bootstrap reduces the CV bias |
sobolnp is a good fit when:
In the reference paper (Solís 2021), 1,000 observations of a hydraulic dyke model gave the same ranking of inputs as classic Monte Carlo estimates based on \(10^5\) model runs, with similar values for the dominant inputs.
Other estimators that work from given data exist, for example the rank- and nearest-neighbour-based estimators in the sensitivity package. What sobolnp adds is a smooth non-parametric fit of every \(\mathbb{E}[Y \mid X_i]\) together with a bandwidth chosen to reduce the bias of the index.
nboot bootstrap
responses. For a candidate bandwidth, the bootstrap fits measure how
much smoothing flattens the curve, and that amount is added back to the
CV curve. The bandwidth is searched below the CV bandwidth, and the
resulting index is reported as the bootstrap estimate.sobolnp() reports both estimates, so you can see how
much the correction matters for each input.
The g-Sobol function is a standard, strongly non-linear benchmark with known indices:
\[ Y = \prod_{i=1}^{4} \frac{|4X_i - 2| + a_i}{1 + a_i}, \qquad X_i \sim \mathcal{U}(0, 1),\quad a = (0, 1, 4.5, 9). \]
library(sobolnp)
a <- c(0, 1, 4.5, 9)
g_sobol <- function(X) {
apply(X, 1, function(x) prod((abs(4 * x - 2) + a) / (1 + a)))
}
set.seed(123)
X <- matrix(runif(4 * 1000), ncol = 4)
Y <- g_sobol(X)
estimation <- sobolnp(Y = Y, X = X, nboot = 100, verbose = FALSE)
estimation
#>
#> Call:
#> sobolnp(Y = Y, X = X, nboot = 100, verbose = FALSE)
#>
#> Number of observations: 1000
#> Number of variables: 4
#>
#> First order indices
#> Si CV bw CV Si Bootstrap bw Bootstrap
#> X1 0.6705288 0.03226 0.700250 0.001465
#> X2 0.1887558 0.04239 0.196459 0.004435
#> X3 0.0174166 0.08971 0.019063 0.009809
#> X4 0.0006614 0.18639 0.001178 0.034906Compared with the exact values:
V <- 1 / (3 * (1 + a)^2)
round(cbind(exact = V / (prod(1 + V) - 1),
CV = estimation$S,
bootstrap = estimation$Sboot), 3)
#> exact CV bootstrap
#> X1 0.716 0.671 0.700
#> X2 0.179 0.189 0.196
#> X3 0.024 0.017 0.019
#> X4 0.007 0.001 0.001plot(estimation)
ckerorder = 4 the
CV estimate is already less biased, and the bootstrap correction can
overshoot. The default (ckerorder = 2) is the recommended
setting.| Argument | Default | Purpose |
|---|---|---|
nboot |
100 |
Bootstrap samples. More is more stable and slower. |
bootstrap |
TRUE |
FALSE returns only the fast CV estimates. |
ckerorder |
2 |
Kernel order (2, 4, 6 or 8). |
bandwidth, bandwidth.compute |
NULL, TRUE |
Starting bandwidths, or fixed ones with
bandwidth.compute = FALSE. |
mc.cores |
1 |
Inputs processed in parallel (Unix-alikes). |
verbose |
TRUE |
Progress messages and bars. |
The cost grows with the number of inputs × nboot. For a
first look at many inputs, run with bootstrap = FALSE, then
bootstrap the relevant ones.
# From CRAN
install.packages("sobolnp")
# Development version
# install.packages("pak")
pak::pak("maikol-solis/sobolnp")If you use sobolnp, please cite (also available with
citation("sobolnp")):
Solís, M. (2021). Non-parametric estimation of the first-order Sobol indices with bootstrap bandwidth. Communications in Statistics - Simulation and Computation, 50(9), 2497–2512. https://doi.org/10.1080/03610918.2019.1655575
MIT © Maikol Solís