| Type: | Package |
| Title: | Intersectional Small Area Estimation from Survey and Census Data |
| Version: | 0.1.0 |
| Description: | Implements design-aware, margin-constrained estimation of population indicators for geographic areas crossed with demographic subgroups. Complex-survey microdata supply outcomes and association information, while one or more aggregate census tables supply overlapping population margins. A generalized iterative proportional fitting engine reconstructs a coherent latent population table, and an augmented model-assisted estimator produces domain means, proportions, and totals for sampled and unsampled intersections. Tools diagnose non-identification, compute linear-programming sensitivity bounds, propagate sampling and model uncertainty with replicate-weight or multiplier bootstrap procedures, enforce structural zeros, and benchmark estimates to official totals. The framework extends calibration ideas from Deville and Sarndal (1992) <doi:10.1080/01621459.1992.10475217> and small area estimation ideas from Fay and Herriot (1979) <doi:10.1080/01621459.1979.10482505>. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| Depends: | R (≥ 4.1.0) |
| Imports: | graphics, stats, utils |
| Suggests: | knitr, lpSolve, rmarkdown, testthat (≥ 3.0.0) |
| VignetteBuilder: | knitr |
| Config/testthat/edition: | 3 |
| RoxygenNote: | 7.3.2 |
| NeedsCompilation: | no |
| Packaged: | 2026-08-24 16:38:42 UTC; marvian |
| Author: | Leila Marvian Mashhad [aut, cre] |
| Maintainer: | Leila Marvian Mashhad <leila.marveian@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-08-25 05:20:31 UTC |
Intersectional Small Area Estimation from Survey and Census Data
Description
The interSAE package combines complex-survey microdata with overlapping aggregate census margins. It reconstructs a coherent latent population table and produces model-assisted estimates for geographic areas crossed with demographic subgroups.
Details
The package separates survey-design declaration, census-margin validation, constrained population reconstruction, and outcome estimation. Optional tools diagnose non-identification, calculate association-sensitivity bounds, bootstrap the complete fitting procedure, and benchmark estimates.
Author(s)
Leila Marvian Mashhad
References
Deville, J.-C. and Sarndal, C.-E. (1992). Calibration estimators in survey sampling. Journal of the American Statistical Association, 87, 376–382. doi:10.1080/01621459.1992.10475217.
Fay, R. E. and Herriot, R. A. (1979). Estimates of income for small places. Journal of the American Statistical Association, 74, 269–277. doi:10.1080/01621459.1979.10482505.
Benchmark Domain Estimates to an Official Aggregate
Description
Apply a common adjustment while reproducing an official population-weighted aggregate. Logit adjustment preserves a bounded response range.
Usage
benchmark_inter(estimates, target, weight = "population",
method = c("logit", "ratio", "additive"), lower = 0, upper = 1)
Arguments
estimates |
A fitted |
target |
Official weighted mean or proportion. |
weight |
Benchmarking-weight column. |
method |
Logit, ratio, or additive adjustment. |
lower, upper |
Range for bounded logit adjustment. |
Value
A data frame with original and benchmarked estimates.
Examples
example_data <- inter_example()
design <- inter_design(example_data$survey, "weight", "area")
margins <- census_margins(example_data$margins)
fit <- fit_inter_sae(unemployed ~ sex + age + residence + area,
design, margins, family = "binomial")
official <- with(example_data$survey,
weighted.mean(unemployed, weight))
benchmarked <- benchmark_inter(fit, official)
attr(benchmarked, "benchmark_achieved")
Fit and Inspect Intersectional Small Area Estimates
Description
Reconstruct a coherent latent joint population table, fit a survey-weighted outcome model, and calculate augmented model-assisted estimates.
Usage
fit_inter_sae(formula, design, margins,
family = c("gaussian", "binomial"), domain = NULL, prior = 0.5,
max_iter = 1000L, tol = 1e-8, residual_correction = TRUE,
max_cells = 1e6, model_args = list())
inter_estimates(object, statistic = c("mean", "total", "both"))
margin_diagnostics(object)
## S3 method for class 'inter_sae'
print(x, ...)
## S3 method for class 'inter_sae'
summary(object, ...)
## S3 method for class 'summary_inter_sae'
print(x, ...)
## S3 method for class 'inter_sae'
plot(x, y = NULL, compare_direct = TRUE, ...)
Arguments
formula |
Outcome model formula. Every predictor must occur among the census-margin dimensions. |
design |
An object returned by |
margins |
An object returned by |
family |
Gaussian or binomial response family. |
domain |
Character vector of output-domain dimensions. |
prior |
Positive seed added to every feasible latent population cell. |
max_iter |
Maximum generalized iterative-proportional-fitting iterations. |
tol |
Relative convergence tolerance. |
residual_correction |
Add a calibrated survey-residual correction. |
max_cells |
Maximum permitted latent-table size. |
model_args |
Optional arguments passed to |
object, x |
A fitted |
statistic |
Extract means/proportions, totals, or both. |
y |
Ignored. |
compare_direct |
Overlay direct survey estimates in the plot. |
... |
Additional printing or plotting arguments. |
Details
For binomial outcomes the working model uses a quasibinomial likelihood so non-integer survey weights are interpreted as analytic weights. Returned estimates remain proportions on the response scale.
Value
fit_inter_sae() returns an inter_sae object.
inter_estimates() and margin_diagnostics() return data frames.
The summary method returns a summary_inter_sae object. The plot method
returns the plotted data invisibly.
Examples
example_data <- inter_example()
design <- inter_design(example_data$survey, "weight", "area",
"strata", "psu")
margins <- census_margins(example_data$margins)
fit <- fit_inter_sae(unemployed ~ sex + age + residence + area,
design, margins, family = "binomial", domain = c("area", "sex"))
head(inter_estimates(fit))
max(margin_diagnostics(fit)$relative_error)
summary(fit)
Diagnose Non-Identification and Compute Sensitivity Bounds
Description
Measure the nullity left by overlapping aggregate margins and, when lpSolve is installed, optimize the target over latent population tables that satisfy the margins and optional association restrictions.
Usage
check_identifiability(object, tol = 1e-9)
identification_bounds(object, domain = NULL, gamma = Inf,
statistic = c("mean", "total"))
inter_sensitivity(object, gamma = c(1, 1.25, 1.5, 2, Inf),
domain = NULL, statistic = c("mean", "total"))
## S3 method for class 'inter_identifiability'
print(x, ...)
## S3 method for class 'inter_bounds'
print(x, ...)
Arguments
object |
A fitted |
tol |
Numerical-rank tolerance. |
domain |
Optional named list defining one target domain. |
gamma |
Association-sensitivity value or vector. One fixes the fitted latent table; infinity imposes census margins only. |
statistic |
Bound a predicted domain mean/proportion or total. |
x |
Object to print. |
... |
Unused. |
Details
Mean bounds use a Charnes–Cooper transformation of the linear-fractional target. They concern uncertainty in the latent census table conditional on the fitted cell predictions; they are not replacements for sampling intervals.
Value
check_identifiability() returns an inter_identifiability object.
identification_bounds() returns an inter_bounds object.
inter_sensitivity() returns a data frame.
Examples
example_data <- inter_example()
design <- inter_design(example_data$survey, "weight", "area")
margins <- census_margins(example_data$margins)
fit <- fit_inter_sae(unemployed ~ sex + age + residence + area,
design, margins, family = "binomial")
check_identifiability(fit)
if (requireNamespace("lpSolve", quietly = TRUE)) {
identification_bounds(fit, domain = list(area = "A1"), gamma = 1.5)
}
Bootstrap and Summarize Uncertainty
Description
Refit population reconstruction and the outcome model under each set of weights. Standard errors include sampling and refitting variation. Identification width can be reported separately.
Usage
inter_bootstrap(object, R = 199L,
type = c("multiplier", "replicate"), seed = 123,
level = 0.95, progress = FALSE)
decompose_uncertainty(object, bootstrap = NULL, bounds = NULL)
## S3 method for class 'inter_bootstrap'
print(x, ...)
Arguments
object |
A fitted |
R |
Number of bootstrap replicates. |
type |
Multiplier or supplied-replicate-weight bootstrap. |
seed |
Random seed for multiplier bootstrap. |
level |
Confidence level. |
progress |
Print periodic progress messages. |
bootstrap |
Optional result from |
bounds |
Optional result from |
x |
Object to print. |
... |
Unused. |
Value
inter_bootstrap() returns an inter_bootstrap object containing a
summary and replicate matrix. decompose_uncertainty() returns a data
frame.
Examples
## Not run:
example_data <- inter_example()
design <- inter_design(example_data$survey, "weight", "area", "strata", "psu")
margins <- census_margins(example_data$margins)
fit <- fit_inter_sae(unemployed ~ sex + age + residence + area,
design, margins, family = "binomial")
boot <- inter_bootstrap(fit, R = 99)
boot
## End(Not run)
Declare Survey Design Information and Census Margins
Description
Validate the two inputs required by fit_inter_sae(). Column names are
supplied as strings to keep programmatic workflows unambiguous.
Usage
inter_design(data, weights, area, strata = NULL, psu = NULL,
replicate_weights = NULL)
census_margins(margins, count = "Freq", structural_zeros = NULL,
tolerance = 1e-8, reconcile = FALSE)
## S3 method for class 'inter_design'
print(x, ...)
## S3 method for class 'census_margins'
print(x, ...)
Arguments
data |
Survey microdata. |
weights |
Name of the survey-weight column. |
area |
Name of the geographic-area column. |
strata |
Optional stratum-column name. |
psu |
Optional primary-sampling-unit column name. |
replicate_weights |
Optional character vector naming replicate-weight columns. |
margins |
A census table or named list of census tables. |
count |
Common name of the population-count column. |
structural_zeros |
Optional data frame of impossible category combinations. Missing values act as wildcards. |
tolerance |
Relative tolerance for equality of census-table totals. |
reconcile |
Whether inconsistent table totals may be proportionally rescaled. |
x |
Object to print. |
... |
Unused. |
Value
inter_design() returns an object of class inter_design.
census_margins() returns an object of class census_margins.
Examples
example_data <- inter_example()
design <- inter_design(example_data$survey, weights = "weight",
area = "area", strata = "strata", psu = "psu")
margins <- census_margins(example_data$margins)
design
margins
Simulate an Intersectional Survey–Census Problem
Description
Create a reproducible problem with a binary unemployment outcome and partially identified age-by-residence associations within area and sex groups.
Usage
simulate_inter_data(seed = 123, n = 500, areas = paste0("A", 1:6))
inter_example()
Arguments
seed |
Random-number seed. |
n |
Survey sample size. |
areas |
Distinct area labels. |
Value
A list containing survey microdata, overlapping census margins, and the latent full population table used to generate the data.
Examples
example_data <- inter_example()
names(example_data)
head(example_data$survey)
lapply(example_data$margins, head)