
Regression with rbbnp
regression.RmdThis article is a guide to conditional-mean kernel regression with
bias_bound_regression().
Estimating a conditional expectation
bias_bound_regression() estimates \(E[Y \mid X=x]\) with bias-aware pointwise
confidence intervals:
bias_bound_regression(
x, # Predictor
y, # Response
eval = NULL, # Evaluation points
bw = "cv", # Positive number, "cv", or "silverman"
conf_level = 0.95,
kernel = "schennach",
control = NULL # Named list of advanced settings
)A basic fit, on data with a quadratic mean and Gaussian noise:
# Generate data: y = f(x) + noise
set.seed(42)
x_data <- runif(250) + runif(250)
y_data <- 2 * x_data - x_data^2 + rnorm(250, sd = 0.3)
# Estimate conditional expectation E[Y|X]
fit <- bias_bound_regression(
x_data,
y_data,
bw = 0.1,
kernel = "schennach"
)
# View results
fit
#> Bias-Bounded Conditional Expectation Estimation
#>
#> Call:
#> bias_bound_regression(x = x_data, y = y_data, bw = 0.1, kernel = "schennach")
#>
#> Sample size: n = 250
#> Bandwidth: h = 0.1000 (user-specified)
#> Kernel: Schennach2004
#>
#> Bias bound parameters:
#> A = 5.2202, r = 2.0000, B = 0.8378
#> bias bounds: b1x = 0.1418, byx = 0.1709
#>
#> Evaluation points: 100 (range: [0.0912, 1.9622])
#> Fitted values: E[Y|X] range [-0.1503, 0.9822]
#> Confidence level: 95%
#>
#> Use summary() for detailed statistics
#> Use plot() to visualize results
#> Use fitted() to extract fitted valuesThe fit is an S3 object of class bbnp_regression. Use
coef() for the key parameters and summary()
for a fuller report:
# Key parameters
coef(fit)
#> A r B h
#> 5.2201734 2.0000000 0.8377779 0.1000000
# Detailed summary
summary(fit)
#> Summary: Bias-Bounded Conditional Expectation Estimation
#> ============================================================
#>
#> Call:
#> bias_bound_regression(x = x_data, y = y_data, bw = 0.1, kernel = "schennach")
#>
#> Sample Information:
#> Sample size (n): 250
#> Bandwidth (h): 0.1000
#> Kernel function: Schennach2004
#>
#> Bias Bound Parameters:
#> A (amplitude): 5.2202
#> r (decay rate): 2.0000
#> B (Y bound): 0.8378
#> b1x (bias f(x)): 0.1418
#> byx (bias f_YX): 0.1709
#> Xi interval: [2.5062, 5.5672]
#>
#> Range Estimation:
#> Fitted values (E[Y|X]):
#> min Q1.25% median mean Q3.75% max
#> -0.1503 0.4949 0.7871 0.6883 0.9281 0.9822
#>
#> Marginal density f(x):
#> min mean max
#> 0.0474 0.5239 1.0028
#>
#> Standard errors:
#> min mean max
#> 0.0268 0.0518 0.1654Visualizing the fit
The default plot shows the estimated mean, its pointwise confidence-interval ribbon, and the original data:
plot(fit)
| Element | Description |
|---|---|
| Estimate (line) | Estimated \(\hat{E}[Y \mid X=x]\) |
| 95% CI (band) | Confidence interval |
| Points | Original data \((X_i, Y_i)\) |
Because the plot returns a ggplot object, you can overlay the true mean for comparison:
# True function for comparison
true_fn <- function(x) 2 * x - x^2
plot(fit) +
stat_function(fun = true_fn, aes(color = "True E[Y|X]"),
linetype = "dashed", linewidth = 1) +
scale_color_manual(values = c("Estimate" = "#08306B", "True E[Y|X]" = "red")) +
labs(color = NULL) +
theme(legend.position = "top")
Fitted values and confidence intervals
fitted() returns the estimated mean at the evaluation
points:
# Get fitted values at evaluation points
predictions <- fitted(fit)
head(predictions, 10)
#> [1] 0.2841416 0.3028584 0.3206543 0.3379210 0.3549087 0.3718462 0.3889071
#> [8] 0.4062110 0.4238766 0.4419718
# Evaluation points
x_points <- fit$x
head(x_points)
#> [1] 0.0911572 0.1100561 0.1289551 0.1478540 0.1667529 0.1856519In regions where the estimated marginal density \(\hat f(x)\) is very close to zero, the
confidence interval may become unbounded (it can contain
-Inf or Inf). This happens because the
conditional mean estimator is a ratio involving \(1/\hat f(x)\). The interval is finite at
interior points, where the density is well away from zero:
# Extract confidence intervals
ci <- confint(fit)
# Show the interval at interior points, where the marginal density is well away
# from zero so the ratio-based interval is finite
ok <- which(is.finite(ci[, "lower"]) & is.finite(ci[, "upper"]))
data.frame(
x = fit$x[ok],
estimate = fitted(fit)[ok],
lower = ci[ok, "lower"],
upper = ci[ok, "upper"]
)[1:6, ]
#> x estimate lower upper
#> 1 0.1100561 0.3028584 -16.5471610 28.347218
#> 2 0.1289551 0.3206543 -4.6771700 8.826715
#> 3 0.1478540 0.3379210 -2.5923395 5.435265
#> 4 0.1667529 0.3549087 -1.7184410 4.040969
#> 5 0.1856519 0.3718462 -1.2338997 3.290189
#> 6 0.2045508 0.3889071 -0.9227982 2.827247Choosing the bandwidth
Set bw to "cv" for cross-validation or
"silverman" for the faster rule-of-thumb selector.
Regression cross-validation minimizes leave-one-out squared
Nadaraya–Watson prediction error, so it uses both x and
y (it is not density cross-validation applied only to
x):
fit_cv <- bias_bound_regression(x_data, y_data, bw = "cv")
cat("CV bandwidth:", coef(fit_cv)["h"])
#> CV bandwidth: 0.1402307Silverman’s predictor-spread rule is a faster alternative. It uses
the same kernel-specific rescaling documented in the density vignette
and, unlike regression CV, does not use y:
fit_silv <- bias_bound_regression(x_data, y_data, bw = "silverman")
cat("Silverman bandwidth:", coef(fit_silv)["h"])
#> Silverman bandwidth: 0.1428276Worked examples
Built-in sample data
# Load the reproducible example
data(two_fold_uniform_example)
head(two_fold_uniform_example)
#> x y
#> 1 1.0859914 2.828175
#> 2 1.6292714 2.014698
#> 3 1.2303920 3.350186
#> 4 1.0686912 1.953532
#> 5 0.8441481 1.391845
#> 6 0.8789330 1.954778
# Estimate regression
fit_real <- bias_bound_regression(
x = two_fold_uniform_example$x,
y = two_fold_uniform_example$y,
bw = 0.1,
kernel = "schennach"
)
# Visualize
plot(fit_real) + ggtitle("Regression on Sample Data")
Comparing kernels
fit_sch <- bias_bound_regression(
x_data, y_data, bw = 0.1, kernel = "schennach"
)
fit_norm <- bias_bound_regression(
x_data, y_data, bw = 0.1, kernel = "normal"
)
grid.arrange(
plot(fit_sch) + ggtitle("Schennach2004 Kernel"),
plot(fit_norm) + ggtitle("Normal Kernel"),
ncol = 1
)
Heteroscedastic errors
The method handles errors whose variance changes with
X:
# Generate heteroscedastic data
set.seed(123)
x_het <- runif(250) + runif(250)
y_het <- x_het^2 + rnorm(250) * x_het # Variance increases with x
fit_het <- bias_bound_regression(x_het, y_het, bw = 0.1)
plot(fit_het) + ggtitle("Heteroscedastic Data")
A polynomial mean
# Quadratic relationship
set.seed(456)
x_poly <- runif(250) + runif(250)
y_poly <- -x_poly^2 + 3 * x_poly + rnorm(250, sd = 0.5)
fit_poly <- bias_bound_regression(x_poly, y_poly, bw = 0.1)
# Compare with true function
true_poly <- function(x) -x^2 + 3*x
plot(fit_poly) +
stat_function(fun = true_poly, aes(color = "True: -x^2 + 3x"),
linetype = "dashed", linewidth = 1) +
scale_color_manual(values = c("Estimate" = "#08306B", "True: -x^2 + 3x" = "red")) +
labs(color = NULL) +
theme(legend.position = "top")
See Also
- Get Started: Quick introduction
- Density Estimation: Density estimation details
- Theory: Mathematical background