# Introduction to rifexpectile

## Motivation

Recentered influence function (RIF) regressions extend the Oaxaca-Blinder decomposition from the mean to other distributional statistics. Applied to quantiles, this requires estimating an inverse density term at each quantile, which can be noisy and irregular, especially in the tails. rifexpectile implements a density-free alternative based on unconditional expectiles: the expectile RIF depends only on primitive moments of the outcome and requires no density estimation, no bandwidth choice, and no kernel smoothing.

The underlying methodology (the closed-form influence function, the two-sample asymptotic theory, and an empirical application) is described in a companion manuscript; this vignette focuses on how to use the package, not on re-deriving that theory.

    library(rifexpectile)

## A first example with simulated data

The package ships with a small simulated data set, `wage_gap_sim`, with a synthetic outcome `logy` observed in two waves (“2000” and “2010”), along with covariates `x1` (continuous) and `x2` (binary), and a stylized sampling weight. No real or proprietary data are used anywhere in this package.

    data(wage_gap_sim)
    head(wage_gap_sim)
    #>   group        y     logy         x1 x2    weight
    #> 1  2000 5661.229 8.641396  0.7677843  1 1.1484742
    #> 2  2000 3417.577 8.136687  1.0126557  0 0.9333160
    #> 3  2000 2850.788 7.955351  1.1053997  0 1.1191789
    #> 4  2000 2283.712 7.733557 -0.1492884  0 1.1719493
    #> 5  2000 3539.620 8.171775  0.9296988  1 1.6370367
    #> 6  2000 1907.758 7.553684 -2.0784772  0 0.7371935

The main function, `rif_decompose()`, takes a formula, a data frame, and the name of the column identifying the two groups to compare:

    fit <- rif_decompose(
      logy ~ x1 + x2,
      data = wage_gap_sim,
      group = "group",
      ref_group = "2000",
      alpha = seq(0.1, 0.9, by = 0.2),
      boot_reps = 100,
      seed = 1
    )
    fit
    #> Density-free RIF-Oaxaca-Blinder decomposition of unconditional expectiles
    #> Groups: '2000' (reference) vs. '2010'  (n = 2000 vs. 2000)
    #> Bootstrap replications: 100
    #>
    #>  alpha  total composition structure
    #>    0.1 0.2241      0.0042    0.2199
    #>    0.3 0.2831      0.0043    0.2788
    #>    0.5 0.3211      0.0043    0.3168
    #>    0.7 0.3563      0.0043    0.3520
    #>    0.9 0.4145      0.0044    0.4102

The `total` column is always exactly the difference of the two groups’ sample expectiles at that level (this is a finite-sample identity, not an approximation, whenever an intercept is included – see `?rif_decompose` for the algebra). The `composition` and `structure` columns are the RIF-regression-based two-fold decomposition of that total into an endowment effect and a returns effect.

    plot(fit, which = "structure")

### Covariate-level detail

The covariate-level composition and structure contributions are available directly, and sum to the aggregate reported above:

    fit$detail_structure
    #>                      0.1         0.3         0.5         0.7         0.9
    #> (Intercept)  0.218822969 0.274841531 0.311810926 0.346230726 0.395926268
    #> x1           0.002500413 0.002945101 0.002913782 0.003024582 0.003303249
    #> x2          -0.001450154 0.001010056 0.002026771 0.002750263 0.010938976
    colSums(fit$detail_structure)  # matches fit$structure
    #>       0.1       0.3       0.5       0.7       0.9
    #> 0.2198732 0.2787967 0.3167515 0.3520056 0.4101685

### Weighted decomposition

Passing a `weights` argument re-estimates the expectile, the RIF, and the regression step using survey weights at every stage:

    fit_w <- rif_decompose(
      logy ~ x1 + x2,
      data = wage_gap_sim,
      group = "group",
      ref_group = "2000",
      alpha = c(0.1, 0.5, 0.9),
      weights = "weight",
      boot_reps = 100,
      seed = 1
    )
    fit_w
    #> Density-free RIF-Oaxaca-Blinder decomposition of unconditional expectiles
    #> Groups: '2000' (reference) vs. '2010'  (n = 2000 vs. 2000)
    #> Bootstrap replications: 100
    #>
    #>  alpha  total composition structure
    #>    0.1 0.2193      0.0011    0.2182
    #>    0.5 0.3158      0.0011    0.3146
    #>    0.9 0.4131      0.0011    0.4119

## A second example with public data

To illustrate the package on a widely used, publicly available data set rather than only a simulated one, this section uses `wage1` from the wooldridge package (Wooldridge, Introductory Econometrics), a standard cross-section of US wages with a `female` indicator – the classic setting for an Oaxaca-Blinder-type decomposition of the gender wage gap.

    data(wage1, package = "wooldridge")
    wage1$group <- ifelse(wage1$female == 1, "female", "male")

    fit_gap <- rif_decompose(
      lwage ~ educ + exper + tenure,
      data = wage1,
      group = "group",
      ref_group = "male",
      alpha = c(0.1, 0.25, 0.5, 0.75, 0.9),
      boot_reps = 200,
      seed = 1
    )
    fit_gap
    #> Density-free RIF-Oaxaca-Blinder decomposition of unconditional expectiles
    #> Groups: 'male' (reference) vs. 'female'  (n = 274 vs. 252)
    #> Bootstrap replications: 200
    #>
    #>  alpha   total composition structure
    #>   0.10 -0.2585     -0.0757   -0.1828
    #>   0.25 -0.3339     -0.0928   -0.2411
    #>   0.50 -0.3972     -0.1066   -0.2906
    #>   0.75 -0.4384     -0.1142   -0.3242
    #>   0.90 -0.4647     -0.1195   -0.3452

    plot(fit_gap, which = "structure")

Here `ref_group = "male"` means the composition term uses male coefficients as the reference and asks how much of the (female - male) gap in log-wage expectiles is attributable to differences in observed characteristics (education, experience, tenure) versus differences in their estimated returns, at each point of the log-wage distribution rather than only at the mean.

## Reproducibility of the underlying data

`simulate_income_data()` is the function used to generate `wage_gap_sim`; the generating script is in `data-raw/wage_gap_sim.R` in the package source, so the bundled example data set can be regenerated or modified directly.

    str(simulate_income_data(n = 5, seed = 42))
    #> 'data.frame':    10 obs. of  6 variables:
    #>  $ group : Factor w/ 2 levels "A","B": 1 1 1 1 1 2 2 2 2 2
    #>  $ y     : num  7085 2246 1403 1659 5706 ...
    #>  $ logy  : num  8.87 7.72 7.25 7.41 8.65 ...
    #>  $ x1    : num  1.371 -0.565 0.363 0.633 0.404 ...
    #>  $ x2    : int  1 0 1 1 0 0 0 1 0 1
    #>  $ weight: num  1.051 0.806 0.805 1.256 0.747 ...