| Title: | Density-Free RIF Decompositions for Unconditional Expectiles |
|---|---|
| Description: | Implements a density-free recentered influence function (RIF) regression framework for unconditional expectiles, and embeds it in a two-sample Oaxaca-Blinder decomposition indexed continuously by the expectile level. Unlike quantile-based RIF decompositions, which require estimating an inverse density term at each quantile, the expectile RIF depends only on primitive moments of the outcome distribution and requires no density estimation, no bandwidth selection, and no kernel smoothing. The package provides expectile estimation by iteratively reweighted least squares, closed-form RIF construction, two-sample composition/structure decomposition across a grid of expectile levels, bootstrap-based inference, and plotting methods. The underlying methodology is described in Ndoye (2025), "Semi-Nonparametric Expectile RIF Regression for Distributional Decomposition," presented at the 2025 World Congress of the Econometric Society, Seoul, Korea, <https://www.econometricsociety.org/regional-activities/conference-papers/view/282/943>. |
| Authors: | Abdoul Aziz Ndoye [aut, cre] |
| Maintainer: | Abdoul Aziz Ndoye <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.1 |
| Built: | 2026-09-30 12:47:29 UTC |
| Source: | https://github.com/aandoye/rifexpectile |
Plots the total, composition, and structure effects across the grid of expectile levels, with bootstrap confidence bands if available.
## S3 method for class 'rifdecomp' plot(x, which = c("total", "composition", "structure"), ...)## S3 method for class 'rifdecomp' plot(x, which = c("total", "composition", "structure"), ...)
x |
An object of class |
which |
One of |
... |
Additional arguments passed to |
Invisibly returns x (the input "rifdecomp" object,
unmodified). Called primarily for its side effect of producing a plot
on the current graphics device.
Decomposes the gap in the -expectile of an outcome between
two groups into a composition (endowment) effect and a structure
(coefficient) effect, at each of a grid of expectile levels, using the
density-free expectile RIF of rif_expectile embedded in a
standard two-fold Oaxaca-Blinder decomposition.
rif_decompose( formula, data, group, ref_group = NULL, alpha = seq(0.1, 0.9, by = 0.1), weights = NULL, boot_reps = 200, conf_level = 0.95, seed = NULL )rif_decompose( formula, data, group, ref_group = NULL, alpha = seq(0.1, 0.9, by = 0.1), weights = NULL, boot_reps = 200, conf_level = 0.95, seed = NULL )
formula |
A formula of the form |
data |
A data frame containing the outcome, covariates, group indicator, and (optionally) weights, for both groups. |
group |
A string naming the column of |
ref_group |
The value of |
alpha |
Numeric vector of expectile levels in |
weights |
Optional string naming a column of |
boot_reps |
Integer, number of bootstrap replications for standard
errors and confidence intervals, stratified by group (each replication
resamples |
conf_level |
Confidence level for the bootstrap percentile
intervals. Default |
seed |
Optional integer seed for the bootstrap random number generator, for reproducibility. |
For each group and expectile level , the
-expectile is estimated by rif_expectile_fit,
the recentered influence function is constructed by
rif_expectile, and a linear regression of the RIF on the
covariates in formula (including an intercept) is estimated by
(weighted) least squares. Writing for the sample mean
covariate vector and for the estimated
coefficients in group , with group B as the reference
group, the two-fold decomposition is
Because an intercept is included, the Total term above coincides exactly (to floating-point precision, not only asymptotically) with the difference of the two sample expectiles; see the package vignette for a demonstration and discussion.
An object of class "rifdecomp", a list with components:
The grid of expectile levels used.
Numeric vectors (one entry per
value of alpha) of the aggregate total, composition, and
structure effects.
Bootstrap standard
errors, or NULL if boot_reps = 0.
Two-column matrices of
bootstrap percentile confidence interval bounds, or NULL if
boot_reps = 0.
Matrices of covariate-level regression
coefficients (rows = covariates including the intercept, columns =
alpha grid) for the reference and comparison groups.
Matrices of covariate-level
composition and structure contributions (same layout as
beta_ref), so that each column sums to the corresponding
aggregate composition/structure entry.
The two group values, in (other, reference) order.
The matched call.
set.seed(42) n <- 500 dat <- data.frame( grp = rep(c("2000", "2010"), each = n), x1 = rnorm(2 * n), x2 = rbinom(2 * n, 1, 0.4) ) dat$y <- with(dat, 1 + 0.5 * x1 + 0.3 * x2 + 0.2 * (grp == "2010") * x1 + rnorm(2 * n, sd = 0.5)) fit <- rif_decompose(y ~ x1 + x2, data = dat, group = "grp", ref_group = "2000", alpha = c(0.1, 0.5, 0.9), boot_reps = 50, seed = 1) print(fit)set.seed(42) n <- 500 dat <- data.frame( grp = rep(c("2000", "2010"), each = n), x1 = rnorm(2 * n), x2 = rbinom(2 * n, 1, 0.4) ) dat$y <- with(dat, 1 + 0.5 * x1 + 0.3 * x2 + 0.2 * (grp == "2010") * x1 + rnorm(2 * n, sd = 0.5)) fit <- rif_decompose(y ~ x1 + x2, data = dat, group = "grp", ref_group = "2000", alpha = c(0.1, 0.5, 0.9), boot_reps = 50, seed = 1) print(fit)
Constructs the recentered influence function (RIF) of the
-expectile at each observation, using the closed-form
expression that depends only on primitive moments of the outcome and
requires no density estimation.
rif_expectile(y, e_alpha, alpha, w = NULL)rif_expectile(y, e_alpha, alpha, w = NULL)
y |
Numeric vector of observations. |
e_alpha |
Numeric scalar, typically the output of
|
alpha |
Numeric scalar in |
w |
Optional numeric vector of sampling weights, the same length as
|
The population influence function of the -expectile is
and the recentered influence function is
.
The empirical RIF used here replaces population quantities with their
weighted sample analogues. By construction, and unlike the quantile RIF,
this expression never requires an estimated density: the denominator is
a sample average of an asymmetric 0/1-type weight, not a density
evaluation. When y and e_alpha come from the same sample
with the same weights, and an intercept is included in any subsequent
regression of the RIF on covariates, the sample mean of the returned
vector equals e_alpha exactly (a finite-sample identity, not an
asymptotic approximation); see the package vignette for a numerical
illustration of this identity and its consequence for two-sample
decompositions.
A numeric vector of the same length as y (after removing
non-finite entries), the recentered influence function evaluated at
each observation.
rif_expectile_fit, rif_decompose
set.seed(1) y <- rlnorm(1000) e50 <- rif_expectile_fit(y, 0.5) r <- rif_expectile(y, e50, 0.5) mean(r) - e50 # approximately 0, exactly 0 up to floating pointset.seed(1) y <- rlnorm(1000) e50 <- rif_expectile_fit(y, 0.5) r <- rif_expectile(y, e50, 0.5) mean(r) - e50 # approximately 0, exactly 0 up to floating point
Computes the sample -expectile of a numeric vector by
iteratively reweighted least squares (IRLS), the standard algorithm for
the asymmetric least-squares problem of Newey and Powell (1987).
rif_expectile_fit(y, alpha, w = NULL, tol = 1e-10, maxit = 500)rif_expectile_fit(y, alpha, w = NULL, tol = 1e-10, maxit = 500)
y |
Numeric vector of observations. |
alpha |
Numeric scalar in |
w |
Optional numeric vector of nonnegative sampling weights, the
same length as |
tol |
Convergence tolerance on successive iterates. Default
|
maxit |
Maximum number of IRLS iterations. Default |
The -expectile of a random variable is
defined as the unique solution to the asymmetric least-squares
minimization problem
Differentiating and setting the first-order condition to zero gives an
estimating equation solved here by IRLS: starting from the sample mean,
each iteration recomputes asymmetric weights
and updates
until convergence.
A numeric scalar, the estimated -expectile.
Newey, W. K. and Powell, J. L. (1987). Asymmetric least squares estimation and testing. Econometrica, 55(4), 819-847.
set.seed(1) y <- rlnorm(1000) rif_expectile_fit(y, 0.5) # approximately mean(y) rif_expectile_fit(y, 0.9) # upper-tail locationset.seed(1) y <- rlnorm(1000) rif_expectile_fit(y, 0.5) # approximately mean(y) rif_expectile_fit(y, 0.9) # upper-tail location
Convenience wrapper computing rif_expectile_fit at several
expectile levels.
rif_expectile_grid(y, alpha, w = NULL, ...)rif_expectile_grid(y, alpha, w = NULL, ...)
y |
Numeric vector of observations. |
alpha |
Numeric vector of expectile levels in |
w |
Optional numeric vector of sampling weights (see
|
... |
Additional arguments passed to |
A named numeric vector of estimated expectiles, one per element
of alpha.
set.seed(1) y <- rlnorm(1000) rif_expectile_grid(y, c(0.1, 0.5, 0.9))set.seed(1) y <- rlnorm(1000) rif_expectile_grid(y, c(0.1, 0.5, 0.9))
Generates a synthetic two-group data set with a log-normal outcome and covariates, group-specific coefficients, and (optionally) sampling weights, for use in examples, tests, and the package vignette. No real or proprietary data are used or required anywhere in this package.
simulate_income_data( n = 1000, group_diff = 0.15, shift = 0.3, sd = 0.4, with_weights = TRUE, seed = NULL )simulate_income_data( n = 1000, group_diff = 0.15, shift = 0.3, sd = 0.4, with_weights = TRUE, seed = NULL )
n |
Integer, number of observations per group. Default |
group_diff |
Numeric scalar controlling how much the two groups'
slope on |
shift |
Numeric scalar added to the second group's intercept (a
stylized aggregate shift). Default |
sd |
Standard deviation of the residual on the log scale. Default
|
with_weights |
Logical; if |
seed |
Optional integer seed for reproducibility. |
The outcome is generated as
with group-specific intercepts and slopes controlled by shift and
group_diff, and drawn from a normal
distribution with standard deviation sd, so that is
log-normal within each group and each covariate combination.
A data frame with columns group (a two-level factor,
"A" and "B"), y (the level of the outcome),
logy (its log), x1 (a continuous covariate), x2
(a binary covariate), and, if with_weights = TRUE, weight.
dat <- simulate_income_data(n = 300, seed = 1) fit <- rif_decompose(logy ~ x1 + x2, data = dat, group = "group", ref_group = "A", boot_reps = 50, seed = 2) print(fit)dat <- simulate_income_data(n = 300, seed = 1) fit <- rif_decompose(logy ~ x1 + x2, data = dat, group = "group", ref_group = "A", boot_reps = 50, seed = 2) print(fit)
A synthetic data set with 2,000 observations per wave ("2000" and
"2010"), generated by simulate_income_data, for use in
examples and the package vignette. No real or proprietary microdata are
used anywhere in this package; this is a purely synthetic illustration
of a stylized structure effect (a group-specific slope shift) combined
with a stylized aggregate shift.
wage_gap_simwage_gap_sim
A data frame with 4,000 rows and 6 columns:
Factor with levels "2000" and "2010".
Numeric, the outcome level (log-normal by construction).
Numeric, log(y).
Numeric, a continuous covariate.
Integer (0/1), a binary covariate.
Numeric, a stylized sampling weight mildly correlated
with x2, included so that weighted and unweighted
decompositions can be compared.
Generated by data-raw/wage_gap_sim.R; see
simulate_income_data for the generating process.
data(wage_gap_sim) fit <- rif_decompose(logy ~ x1 + x2, data = wage_gap_sim, group = "group", ref_group = "2000", boot_reps = 50, seed = 1) print(fit)data(wage_gap_sim) fit <- rif_decompose(logy ~ x1 + x2, data = wage_gap_sim, group = "group", ref_group = "2000", boot_reps = 50, seed = 1) print(fit)