Nothing
expect_error(get_bw(5))
expect_error(get_bw("no_kernel"))
expect_silent(get_bw("HS"))
expect_silent(get_bw("GR"))
test_that("every built-in kernel defaults to a closed-form rule", {
expect_equal(get_standard_bw("gcopula", "uniform"), "SJ")
expect_equal(get_standard_bw("gcopula", "constant"), "SJ")
expect_equal(get_standard_bw("gcopula", "beta"), "SJ")
expect_equal(get_standard_bw("beta", "uniform"), "HS")
expect_equal(get_standard_bw("beta", "constant"), "HS")
expect_equal(get_standard_bw("beta", "gaussian"), "HS")
expect_equal(get_standard_bw("beta_biased", "beta"), "HS")
expect_equal(get_standard_bw("gamma", "normal"), "GR")
expect_equal(get_standard_bw("gamma", "uniform"), "GR")
expect_equal(get_standard_bw("gamma_biased", "gamma"), "GR")
expect_equal(get_standard_bw("normal", "normal"), "RHE")
expect_equal(get_standard_bw("uniform", "normal"), "RHE")
expect_equal(get_standard_bw("epanechnikov", "constant"), "nrd0")
expect_equal(get_standard_bw("triangular", "uniform"), "nrd0")
add_kernel("asymmetric_custom", list(
kernel = function(y, x, h) stats::dgamma(x, y / h + 1, scale = h) * h,
support = c(0, Inf)
))
expect_equal(get_standard_bw("asymmetric_custom", "uniform"), "ucv")
})
set.seed(123)
gamma_ucv_sample <- rgamma(60, 2, 2)
## Regression pin for Chen's modified gamma kernel with the normalized UCV
## criterion (2.0.0). For this sample the ISE-optimal bandwidth is about 0.11.
expect_equal(
get_bw("ucv")(gamma_ucv_sample, "gamma", "uniform", c(0, Inf)),
0.10778523669076044,
tolerance = 1e-8
)
set.seed(1)
regular_beta_sample <- rbeta(200, 2, 5)
hs_value <- get_bw("HS")(regular_beta_sample, "beta", "uniform", c(0, 1))
expect_gt(hs_value, 0)
## Regression pin for the closed-form HS path; recomputed manually from
## the alpha/beta moment fit at seed = 1.
expect_equal(hs_value, 0.0209275823, tolerance = 1e-8)
set.seed(1)
rhe_sample <- rnorm(500)
## Regression pin for the inlined Hermite polynomial RHE selector;
## matches the previous EQL-based implementation to ~1e-12.
expect_equal(get_bw("RHE")(rhe_sample), 0.4314342622, tolerance = 1e-8)
set.seed(1)
boundary_beta_sample <- rbeta(200, 0.5, 0.5)
expect_warning(
get_bw("HS")(boundary_beta_sample, "beta", "uniform", c(0, 1)),
"fallback heuristic"
)
expect_error(get_bw("HS")("not numeric", "beta", "uniform", c(0, 1)), "'x' must be a numeric vector.")
expect_error(get_bw("HS")(0.5, "beta", "uniform", c(0, 1)), "at least 2 observations")
expect_error(get_bw("HS")(c(-0.1, 0.2), "beta", "uniform", c(0, 1)), "must be in \\[0, 1\\]")
expect_error(compute_hs_bandwidth(c(0, 1, NA)), "No data strictly within")
expect_error(compute_hs_bandwidth(c(0.4, 0.4, 0.4)), "Sample variance is zero.")
set.seed(42)
gamma_reference_sample <- rgamma(300, shape = 3.2, rate = 1.7)
## Regression pin. The fitted shape (2.84) is below 3, so the floor applies;
## before 2.0.0 this sample gave 0.070709052899177.
expect_equal(
get_bw("GR")(
gamma_reference_sample, "gamma", "uniform", c(0, Inf)
),
0.067252214229985,
tolerance = 1e-10
)
expect_error(
get_bw("GR")(gamma_reference_sample, "beta", "uniform", c(0, 1)),
"only defined for the gamma kernels"
)
expect_equal(
get_bw("GR")(gamma_reference_sample, "gamma_biased", "uniform", c(0, Inf)),
get_bw("GR")(gamma_reference_sample, "gamma", "uniform", c(0, Inf))
)
expect_error(
compute_gr_bandwidth(c(-1, 1, 2)),
"non-negative"
)
expect_error(
compute_gr_bandwidth(c(0, 0, 1)),
"At least 2 observations must be strictly positive"
)
expect_error(
compute_gr_bandwidth("not numeric"),
"numeric vector"
)
expect_error(
compute_gr_bandwidth(1),
"at least 2 observations"
)
expect_error(
compute_gr_bandwidth(rep(2, 3)),
"gamma reference fit is degenerate"
)
expect_error(
compute_gr_bandwidth(c(.Machine$double.xmin, 1)),
"did not converge"
)
test_that("GR floors the fitted gamma shape at 3 and keeps the mean", {
# Chen's AMISE bandwidth for a Gamma(shape, rate) reference, written out.
gr_formula <- function(shape, rate, n) {
v <- sqrt(rate) * gamma(shape - 0.5) / gamma(shape)
r <- rate^3 * gamma(2 * shape - 3) / 2^(2 * shape - 3) / gamma(shape)^2 *
(shape - 1) * (3 * shape - 4) / 4
(v / (2 * sqrt(pi) * r * n))^(2 / 5)
}
# Exponential-like data: fitted shape near 1, floored at 3.
x <- qgamma(ppoints(100), shape = 1, rate = 2)
expect_lt(get_start("gamma")$estimator(x)[["shape"]], 3)
expect_equal(compute_gr_bandwidth(x), gr_formula(3, 3 / mean(x), 100),
tolerance = 1e-10
)
# Above the floor the fitted shape is used as is.
y <- qgamma(ppoints(200), shape = 6, rate = 2)
fit <- get_start("gamma")$estimator(y)
expect_equal(compute_gr_bandwidth(y),
gr_formula(fit[["shape"]], fit[["shape"]] / mean(y), 200),
tolerance = 1e-6
)
# Exact zeros are dropped from the reference fit but counted in n.
expect_equal(compute_gr_bandwidth(c(0, y)),
gr_formula(fit[["shape"]], fit[["shape"]] / mean(y), 201),
tolerance = 1e-6
)
})
test_that("SJ for the Gaussian copula kernel works on the probit scale", {
set.seed(3)
x <- rbeta(300, 2, 5)
h <- get_bw("SJ")(x, "gcopula", "uniform", c(0, 1))
s <- stats::bw.SJ(stats::qnorm(x))
# The copula kernel's probit-scale sd sqrt(1 - rho^2) equals the SJ bandwidth.
rho <- 1 - h^2
expect_equal(sqrt(1 - rho^2), s, tolerance = 1e-12)
# Observations at the boundary are dropped, as in JH.
expect_equal(get_bw("SJ")(c(0, x, 1), "gcopula", "uniform", c(0, 1)), h)
# Other kernels keep stats::bw.SJ on the data scale.
expect_equal(get_bw("SJ")(x, "gaussian", "uniform", c(-Inf, Inf)), stats::bw.SJ(x))
# Degenerate data fall back to JH with a warning.
expect_warning(
fallback <- get_bw("SJ")(rep(0.4, 5), "gcopula", "uniform", c(0, 1)),
"Falling back to 'JH'"
)
expect_equal(fallback, bw_environment$JH(rep(0.4, 5)))
# Very wide probit-scale bandwidths are capped at the independence copula.
expect_equal(compute_probit_sj_bandwidth(pnorm(c(-8, 8))), 1)
})
expect_error(
kdensity_sq(
x = c(0.2, 0.8),
h = 0.1,
kernel_fun = function(y, x, h) stop("boom"),
parametric_start = function(x) rep(1, length(x)),
parametric_start_data = c(1, 1),
parametric_start_vector = function(y) rep(1, length(y)),
support = c(0, 1)
),
"Normalization error: The function will not integrate"
)
expect_error(
kdensity(mtcars$mpg, kernel = "uniform", start = "gamma"),
"Normalization error: The function will not integrate.Two common causes are: 1.) The kernel is non-smooth, try a smooth kernel if possible. 2.) The supplied support is incorrect."
)
test_that("the UCV objective normalizes both terms", {
# Independent reference: integral of the squared normalized estimate minus
# twice the mean leave-one-out estimate, divided by the full-data normalizer.
ucv_reference <- function(x, h, kernel_name, start_name) {
kernel <- get_kernel(kernel_name)$kernel
start <- get_start(start_name)
dstart <- function(data, estimates) {
do.call(start$density, c(list(data), as.list(estimates)))
}
full <- start$estimator(x)
unnormalized <- function(y) {
vapply(y, function(point) {
mean(kernel(point, x, h) / h / dstart(x, full)) * dstart(point, full)
}, numeric(1))
}
normalization <- integrate(unnormalized, 0, Inf)$value
term1 <- integrate(function(y) (unnormalized(y) / normalization)^2, 0, Inf)$value
loo <- vapply(seq_along(x), function(i) {
estimates <- start$estimator(x[-i])
mean(kernel(x[i], x[-i], h) / h / dstart(x[-i], estimates)) *
dstart(x[i], estimates)
}, numeric(1))
term1 - 2 * mean(loo) / normalization
}
set.seed(20261028)
x <- rgamma(40, 2, 2)
cases <- list(
c("gamma", "uniform"),
c("gamma_biased", "uniform"),
c("gamma", "gamma"),
c("gamma", "invgauss")
)
for (case in cases) {
objective <- make_ucv_objective(x, case[[1]], case[[2]], c(0, Inf))
for (h in c(0.05, 0.2, 0.6)) {
expect_equal(objective(h), ucv_reference(x, h, case[[1]], case[[2]]),
tolerance = 1e-5, info = paste(case[[1]], case[[2]], h)
)
}
}
# A failing compiled leave-one-out fit must fall back to the R path, which
# gives the same criterion.
local_mocked_bindings(
make_compiled_loo_parameters = function(...) stop("compiled fit failed")
)
objective <- make_ucv_objective(x, "gamma", "gamma", c(0, Inf))
expect_equal(objective(0.2), ucv_reference(x, 0.2, "gamma", "gamma"),
tolerance = 1e-5
)
})
test_that("UCV uses kernel-scale pilots and caps its search interval", {
local_mocked_bindings(
compute_gr_bandwidth = function(x) 0.02,
compute_hs_bandwidth = function(x) {
warning("fallback heuristic")
0.08
},
compute_probit_sj_bandwidth = function(x) 0.2
)
check_interval <- function(kernel, start, lower, upper) {
local_mocked_bindings(make_ucv_objective = function(...) {
function(h) (h - (lower + upper) / 2)^2
})
expect_silent(value <- bw_environment$ucv(seq(0.1, 0.9, length.out = 20),
kernel, start, c(0, 1)))
expect_equal(value, (lower + upper) / 2, tolerance = 1e-8)
}
for (kernel in c("gamma", "gamma_biased")) {
check_interval(kernel, "gamma", 0.004, 0.1)
}
for (kernel in c("beta", "beta_biased")) {
check_interval(kernel, "uniform", 0.016, 0.25 - 1e-10)
}
check_interval("gcopula", "beta", 0.04, 0.5)
})
test_that("UCV retains legacy pilots when a rule fails", {
x <- seq(0.1, 0.9, length.out = 20)
local_mocked_bindings(
compute_gr_bandwidth = function(...) stop("pilot failed"),
compute_hs_bandwidth = function(...) stop("pilot failed"),
compute_probit_sj_bandwidth = function(...) stop("pilot failed"),
make_ucv_objective = function(...) function(h) stop("objective failed")
)
for (kernel in c("beta", "beta_biased", "gcopula")) {
expect_warning(value <- bw_environment$ucv(x, kernel, "uniform", c(0, 1)),
"Using 'JH'")
expect_equal(value, bw_environment$JH(x))
}
expect_warning(value <- bw_environment$ucv(x, "gamma", "uniform", c(0, Inf)),
"Using 'nrd0'")
expect_equal(value, stats::bw.nrd0(x))
expect_warning(value <- bw_environment$ucv(x, "gamma_biased", "gamma", c(0, Inf)),
"Using 'RHE'")
expect_equal(value, bw_environment$RHE(x))
# The same pilots still apply to custom kernels and symmetric parametric fits.
expect_warning(value <- bw_environment$ucv(x, "asymmetric_custom", "uniform", c(0, Inf)),
"Using 'nrd0'")
expect_equal(value, stats::bw.nrd0(x))
expect_warning(value <- bw_environment$ucv(x, "gaussian", "normal", c(-Inf, Inf)),
"Using 'RHE'")
expect_equal(value, bw_environment$RHE(x))
})
test_that("UCV warns at either search edge and returns its pilot on failure", {
x <- seq(0.1, 0.9, length.out = 20)
local_mocked_bindings(compute_gr_bandwidth = function(...) 0.1)
for (direction in c(-1, 1)) {
local_mocked_bindings(make_ucv_objective = function(...) function(h) direction * h)
expect_warning(value <- bw_environment$ucv(x, "gamma", "gamma", c(0, Inf)),
"at the edge of its search interval \\[0.02, 0.5\\]")
expect_lt(abs(value - if (direction == 1) 0.02 else 0.5), 1e-4)
}
local_mocked_bindings(make_ucv_objective = function(...) function(h) stop("failed"))
expect_warning(value <- bw_environment$ucv(x, "gamma", "gamma", c(0, Inf)),
"Using 'GR'")
expect_equal(value, 0.1)
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.