Algorithm to estimate the Sobol indices using a non-parametric
fit of the regression curve. The bandwidth is estimated using bootstrap
to reduce the finite-sample bias. The package is based on the paper
Solís, M. (2021)
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.034906
Compared 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.001
plot(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