getting-started

library(wavecov)

Overview

The wavecov package provides overlap-aware comparisons of workforce metrics between two waves of data. This vignette shows the core scalar API, compare_waves(), on a minimal example.

We assume a long panel with one row per employee-wave-metric:

dat <- data.frame(
  eeid   = c("a", "b", "c",  "a",  "b",  "c"),
  wave   = c(0,   0,   0,    1,    1,    1),
  metric = c(1.0, 2.0, 3.0,
             1.2, 2.1, 2.9)
)

dat
#>   eeid wave metric
#> 1    a    0    1.0
#> 2    b    0    2.0
#> 3    c    0    3.0
#> 4    a    1    1.2
#> 5    b    1    2.1
#> 6    c    1    2.9

Basic scalar comparison

The simplest use case is a single metric between two waves:

res_linked <- compare_waves(
  data       = dat,
  wave_0     = 0,
  wave_1     = 1,
  id_col     = "eeid",
  wave_col   = "wave",
  metric_col = "metric",
  method     = "linked"
)

res_linked
#> $estimate
#> [1] 0.06666667
#> 
#> $se
#> [1] 0.08819171
#> 
#> $ci
#> [1] -0.1061859  0.2395192
#> 
#> $level
#> [1] 0.95
#> 
#> $N0
#> [1] 3
#> 
#> $N1
#> [1] 3
#> 
#> $nS
#> [1] 3
#> 
#> $overlap
#> [1] 1
#> 
#> $method
#> [1] "linked"
#> 
#> $V0_bar
#> [1] 0.3333333
#> 
#> $V1_bar
#> [1] 0.2411111
#> 
#> $C01_bar
#> [1] 0.2833333
#> 
#> $V0_ind
#> [1] 1
#> 
#> $V1_ind
#> [1] 0.7233333
#> 
#> $C01_ind
#> [1] 0.85
#> 
#> $sigma2
#> NULL
#> 
#> $reliability
#> NULL
#> 
#> $ci_lower
#> [1] -0.1061859
#> 
#> $ci_upper
#> [1] 0.2395192
#> 
#> attr(,"class")
#> [1] "wavecov_result"

The result is a wavecov_result object with:

  • estimate: change in the metric between wave 0 and wave 1.
  • se: standard error of the change estimate.
  • ci_lower, ci_upper: lower/upper confidence limits at the requested level.
  • N0, N1: counts in wave 0 and wave 1.
  • nS: number of “stayers” (ids present in both waves).
  • method: the estimation method actually used.

You can pull individual fields:

res_linked$estimate
#> [1] 0.06666667
res_linked$se
#> [1] 0.08819171
c(res_linked$ci_lower, res_linked$ci_upper)
#> [1] -0.1061859  0.2395192

When linked data is not available

If stayer information is unavailable or individual-level data are not available, the linked method cannot be used. In that case, you can either specify method = "reliability" directly, or let method = "auto" choose between linked, reliability, and bounds. The example below uses a case where individual data is available at both waves, but information on stayers has been lost (e.g., due to anonymized records). The user should note that reliability should reflect temporal stability for this use case.

dat_no_stayers <- data.frame(
  eeid   = c("a", "b", "c",  "d",  "e",  "f"),
  wave   = c(0,   0,   0,    1,    1,    1),
  metric = c(1.0, 2.0, 3.0,
             1.5, 2.2, 3.1)
)

# Auto will fall back to reliability or bounds as needed
res_auto <- compare_waves(
  data        = dat_no_stayers,
  wave_0      = 0,
  wave_1      = 1,
  id_col      = "eeid",
  wave_col    = "wave",
  metric_col  = "metric",
  method      = "auto",
  reliability = 0.8
)

res_auto$method
#> [1] "reliability"
res_auto$estimate
#> [1] 0.2666667
c(res_auto$ci_lower, res_auto$ci_upper)
#> [1] -1.183942  1.717275

When only bounds are possible

In some cases we neither have stayer information available nor are willing to assume a reliability. In that setting, compare_waves() can fall back to Cauchy-based bounds, which describe a range of possible changes consistent with the data instead of a single point estimate.

Setting method = "bounds" forces this behaviour:

dat_bounds <- data.frame(
  eeid   = c("a", "b", "c",  "d",  "e",  "f"),
  wave   = c(0,   0,   0,    1,    1,    1),
  metric = c(1.0, 2.0, 3.0,
             1.5, 2.2, 3.1)
)

res_bounds <- compare_waves(
  data       = dat_bounds,
  wave_0     = 0,
  wave_1     = 1,
  id_col     = "eeid",
  wave_col   = "wave",
  metric_col = "metric",
  method     = "bounds",
  cov_sign   = "unrestricted",
  overlap_mode = "generic"
)

res_bounds
#> $estimate
#> [1] 0.2666667
#> 
#> $se_lower
#> [1] 0.1142688
#> 
#> $se_upper
#> [1] 1.040432
#> 
#> $var_lower
#> [1] 0.01305736
#> 
#> $var_upper
#> [1] 1.082498
#> 
#> $level
#> [1] 0.95
#> 
#> $N0
#> [1] 3
#> 
#> $N1
#> [1] 3
#> 
#> $nS
#> [1] 0
#> 
#> $overlap
#> [1] 0
#> 
#> $cov_sign
#> [1] "unrestricted"
#> 
#> $overlap_mode
#> [1] "generic"
#> 
#> $method
#> [1] "bounds"
#> 
#> $ci_lower
#> [1] NA
#> 
#> $ci_upper
#> [1] NA
#> 
#> attr(,"class")
#> [1] "wavecov_bounds_result"

A wavecov_bounds_result object does not commit to a single change estimate; instead it reports bounds implied by the observed wave-level variances and any assumptions you specify (cov_sign, overlap_mode, and optionally sigma2S). This is appropriate when composition change is large and we lack enough structure for a defensible point estimate.

Summary

Use compare_waves() when you want a single, well-understood comparison between two waves for one metric and (optionally) one population slice. The companion compare_waves_batch() wrapper (see the Panel comparisons vignette) generalizes this to many groups and metrics.