---
title: "complexr: Analysis of Complex Survey Data"
author: "Stalyn Guerrero Gómez"
date: "`r Sys.Date()`"
output:
  rmarkdown::html_vignette:
    toc: true
    toc_depth: 3
    number_sections: true
    fig_width: 8
    fig_height: 5
vignette: >
  %\VignetteIndexEntry{complexr: Analysis of Complex Survey Data}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
bibliography: references.bib
---

```{r}
#| label: setup
#| include: false
knitr::opts_chunk$set(
  collapse  = TRUE,
  comment   = "#>",
  message   = FALSE,
  warning   = FALSE,
  fig.align = "center"
)
```

## Overview {.unnumbered}

**complexr** is an R package that provides a tidy-oriented
framework for the analysis of complex survey data. It supports:

- Reading microdata from multiple file formats (CSV, XLSX, SPSS, Stata, RDS)
- Constructing and diagnosing stratified and clustered sampling designs
- Estimating population means, totals, proportions, ratios, and quantiles
  with correct variance estimation under complex designs
- Deriving new variables from existing survey data
- Launching an interactive Shiny application for point-and-click analysis

All estimation functions account for stratification, clustering, and
unequal sampling weights following the linearization approach described in
@lumley2010 and @sarndal1992.

---

## Conceptual Framework and Notation {#sec-notation}

This section establishes the statistical notation used throughout the
vignette, following the conventions of @gutierrez2025.

### Population and Sample

Let $U = \{1, 2, \ldots, N\}$ be the **finite population** of size $N$,
and $s \subset U$ the **sample** selected under a probability design
$p(s)$. For each unit $k \in U$, $y_k$ denotes the value of the variable
of interest. The **population total** and **population mean** are defined
respectively as:

$$
Y = \sum_{k \in U} y_k, \qquad \bar{Y} = \frac{Y}{N}.
$$

### Design Weights and Adjusted Weights

The inclusion probability of unit $k$ is $\pi_k = \Pr(k \in s) > 0$.
The **basic design weight** is $d_k = 1/\pi_k$. In practice these weights
are modified to incorporate non-response adjustments or calibration to
known population totals, yielding **adjusted weights** $w_k$. Throughout
this documentation, $w_k$ refers to the final weights available in the
microdata file (variable `weight`).

### Horvitz–Thompson Estimator

The Horvitz–Thompson (HT) estimator of the population total is
[@horvitz1952]:

$$
\hat{Y}_{HT} = \sum_{k \in s} d_k\, y_k,
$$

and the estimated population size is:

$$
\hat{N}_{HT} = \sum_{k \in s} d_k.
$$

When working with adjusted weights $w_k$, the weighted HT estimator
takes the form $\hat{Y}_w = \sum_{k \in s} w_k\, y_k$.

### Design-Based Variance

The variance of the HT estimator is estimated as [@sarndal1992]:

$$
\hat{V}_p\!\left(\hat{Y}_{HT}\right) =
\sum_{k \in s}\sum_{l \in s}
\bigl(d_k d_l - d_{kl}\bigr)\, y_k\, y_l,
$$

where $d_{kl} = 1/\pi_{kl}$ and $\pi_{kl} = \Pr(k, l \in s)$ are the
second-order inclusion probabilities. In practice, equivalent methods
such as **Taylor linearization** or **replication** (*jackknife*,
*bootstrap*) are used because they do not require explicit computation
of $\pi_{kl}$.

### Stratified Multistage Design

For a design with $H$ strata, $\alpha_h$ primary sampling units (PSUs)
in stratum $h$, and $n_{h\alpha}$ observations in PSU $\alpha$, the
total estimator is:

$$
\hat{Y}_{HT} = \sum_{h=1}^{H}\sum_{\alpha=1}^{\alpha_h}
\sum_{k=1}^{n_{h\alpha}} \omega_{h\alpha k}\, y_{h\alpha k},
$$

where $\omega_{h\alpha k}$ is the adjusted weight of individual $k$ in
PSU $\alpha$ of stratum $h$.

### Design Effect (DEFF)

Following @kish1965, the design effect is defined as the ratio of the
estimator variance under the complex design to the variance of the same
estimator under simple random sampling (SRS) of the same size:

$$
\widehat{\text{DEFF}} =
\frac{\hat{V}_p(\hat{\theta})}{\hat{V}_{\text{SRS}}(\hat{\theta})}.
$$

A value $\widehat{\text{DEFF}} > 1$ indicates that the complex design
inflates variance relative to SRS, while $\widehat{\text{DEFF}} < 1$
signals an efficiency gain, typically arising from effective
stratification.


## Installation

```{r}
#| label: install
#| eval: false
# Install from GitHub
# install.packages("remotes")
remotes::install_github("stalynGuerrero/complexr")
```

```{r}
#| label: load
library(complexr)
```

---

## Simulated Data

The package ships with `generate_example_data()`, which generates a
three-level hierarchical dataset (PSUs → households → individuals)
representative of a stratified multistage survey design.

```{r}
#| label: gen-data
data <- generate_example_data(n_upm = 100, seed = 123)
dplyr::glimpse(data)
```

### Variables

| Variable | Type | Description |
|---|---|---|
| `strata` | character | Stratum identifier ($h = 1,\ldots,H$) |
| `upm` | character | Primary sampling unit $\alpha$ within stratum $h$ |
| `hogar_id` | character | Household identifier |
| `persona_id` | character | Individual identifier $k$ |
| `weight` | numeric | Adjusted weight $w_k$ (inverse inclusion probability, calibrated) |
| `region` | character | Estimation domain: North / Center / South |
| `sexo` | character | Sex: Male / Female |
| `area` | character | Area: Urban / Rural |
| `edad` | numeric | Age in years |
| `educacion` | factor | Education level: Primary / Secondary / Higher |
| `empleo` | factor | Employment status: Formal / Informal / Unemployed |
| `ingreso_pc` | numeric | Per-capita household income ($y_k$) |
| `gasto_pc` | numeric | Per-capita household expenditure |
| `pobre` | numeric | Binary poverty indicator: $y_k \in \{0, 1\}$ |
| `ingreso2` | numeric | Auxiliary income variable (10 % missing values) |

### Hierarchy and Internal Consistency

The simulation enforces the following constraints:

- Weights are constant within households:
  $w_{h\alpha k} = w_{h\alpha}$ for all $k$ in the household.
- Per-capita income is constant within households:
  $y_{h\alpha k} = Y_{h\alpha} / N_{h\alpha}$.
- Individuals younger than 5 years have `NA` for education.

Household income follows a hierarchical gamma model with PSU and
household random effects:

$$
Y_{h\alpha} \sim \text{Gamma}\!\left(\alpha_0,\;
\beta_0 \cdot \exp(u_{h\alpha} + v_{h\alpha k})\right)
$$

where $u_{h\alpha} \sim N(0, 0.09)$ is the PSU effect and
$v_{h\alpha k} \sim N(0, 0.04)$ is the household effect.


## Reading External Data

To load your own microdata use `read_survey_data()`. Supported formats
are detected automatically from the file extension.

```{r}
#| label: read-data
#| eval: false
# CSV
data <- read_survey_data("survey.csv")

# SPSS
data <- read_survey_data("survey.sav")

# Stata
data <- read_survey_data("survey.dta")

# Excel
data <- read_survey_data("survey.xlsx")
```

The function returns the data as a `tibble` and attaches metadata
attributes: `source_path`, `source_format`, `n_rows`, `n_cols`.


## Deriving Variables

`mutate_survey_data()` creates new variables from a named list of
one-sided formulas, evaluated sequentially in the environment of the
data frame.

```{r}
#| label: mutate
data <- mutate_survey_data(
  data,
  definitions = list(
    log_ingreso = ~ log(ingreso_pc + 1),
    ratio_gasto = ~ gasto_pc / ingreso_pc
  )
)

dplyr::select(data, ingreso_pc, log_ingreso, ratio_gasto) |> head(4)
```


## Survey Design

### Building a Design Object

`as_survey_design_tbl()` wraps `survey::svydesign()` and returns a
`tbl_svy` object compatible with the **srvyr** / **survey** ecosystem
[@lumley2010].

```{r}
#| label: design
design <- as_survey_design_tbl(
  data    = data,
  weight  = "weight",
  strata  = "strata",
  cluster = "upm",
  nest    = TRUE
)

class(design)
```

Supported configurations:

| Configuration | Arguments |
|---|---|
| Simple random sampling (SRS) | `weight` only |
| Stratified | `weight` + `strata` |
| Clustered (single-stage) | `weight` + `cluster` |
| Stratified multistage | `weight` + `strata` + `cluster` |
| With finite population correction | any of the above + `fpc` |

The function validates that weights $w_k$ are strictly positive
($w_k > 0$) and free of missing values, and optionally checks that PSUs
are not shared across strata (`check_psu = TRUE`).

> **Note:** When a stratum $h$ contains only one PSU ($\alpha_h = 1$), estimation
> of $\hat{V}_p$ by Taylor linearization is undefined. The function
> automatically sets `options(survey.lonely.psu = "adjust")` to use the
> conservative centered-at-stratum-mean approximation [@cochran1977].

### Diagnosing the Design

```{r}
#| label: describe
describe_survey_design(design)
```

The diagnostic table reports:

| Column | Description |
|---|---|
| `n_obs` | Total sample size $n = \lvert s \rvert$ |
| `n_strata` | Number of strata $H$ |
| `n_clusters` | Total number of PSUs $\sum_h \alpha_h$ |
| `weight_min` | $\min_{k \in s} w_k$ |
| `weight_max` | $\max_{k \in s} w_k$ |
| `weight_mean` | $\bar{w} = \hat{N}_w / n$ |
| `weight_cv` | $CV(w) = s_w / \bar{w}$ |


## Estimation

All estimators are computed with `estimate_survey()`. The function returns
a `tibble` with the following columns:

| Column | Description |
|---|---|
| `variable` | Name of the target variable |
| `estimator` | Type of estimator |
| `estimate` | Point estimate $\hat{\theta}$ |
| `se` | Standard error $ee(\hat{\theta}) = \sqrt{\hat{V}_p(\hat{\theta})}$ |
| `cv` | Coefficient of variation $CV = ee(\hat{\theta})/\hat{\theta}$ |
| `deff` | Design effect $\widehat{\text{DEFF}}$ |
| `lci` | Lower confidence bound |
| `uci` | Upper confidence bound |
| `quality` | Precision label based on $CV$ |

**Precision labels** (based on the coefficient of variation):

| $CV$ | Label |
|---|---|
| $< 5\%$ | Very high precision |
| $5\%$–$10\%$ | High precision |
| $10\%$–$20\%$ | Acceptable precision |
| $20\%$–$30\%$ | Use with caution |
| $\geq 30\%$ | Low precision |

### Population Mean

The weighted total and estimated population size are:

$$
\hat{Y}_w = \sum_{k \in s} w_k\, y_k,
\qquad
\hat{N}_w = \sum_{k \in s} w_k.
$$

The **weighted mean** (Horvitz–Thompson ratio estimator) is:

$$
\bar{y}_w = \frac{\hat{Y}_w}{\hat{N}_w}
= \frac{\displaystyle\sum_{k \in s} w_k\, y_k}
       {\displaystyle\sum_{k \in s} w_k}.
$$

Its variance is estimated by Taylor linearization [@sarndal1992]:

$$
\hat{V}_p\!\left(\bar{y}_w\right) =
\frac{1}{\hat{N}_w^2}\,\hat{V}_p\!\left(\hat{Y}_w\right).
$$

```{r}
#| label: mean
r_mean <- estimate_survey(
  design    = design,
  variable  = "ingreso_pc",
  estimator = "mean"
)
r_mean
```

### Population Total

Under a stratified multistage design, the HT total estimator is:

$$
\hat{Y}_w =
\sum_{h=1}^{H}\sum_{\alpha=1}^{\alpha_h}\sum_{k=1}^{n_{h\alpha}}
\omega_{h\alpha k}\, y_{h\alpha k}.
$$

Its variance is estimated stratum by stratum:

$$
\hat{V}_p\!\left(\hat{Y}_w\right) =
\sum_{h=1}^{H}
\hat{V}_{p,h}\!\left(\hat{Y}_{w,h}\right),
$$

where $\hat{V}_{p,h}$ is computed within each stratum $h$ using the
deviations of PSU totals from their stratum mean.

```{r}
#| label: total
r_total <- estimate_survey(
  design    = design,
  variable  = "ingreso_pc",
  estimator = "total"
)
r_total
```

### Proportions

#### Binary Variable

For an indicator variable $y_k \in \{0, 1\}$, the **population
proportion** $\pi$ is estimated as [@heeringa2017]:

$$
\hat{p} =
\frac{\displaystyle\sum_{h=1}^{H}\sum_{\alpha=1}^{\alpha_h}
\sum_{k=1}^{n_{h\alpha}} \omega_{h\alpha k}\, I(y_k = 1)}
{\displaystyle\sum_{h=1}^{H}\sum_{\alpha=1}^{\alpha_h}
\sum_{k=1}^{n_{h\alpha}} \omega_{h\alpha k}}
= \frac{\hat{N}_1}{\hat{N}_w}.
$$

The variance of $\hat{p}$ is approximated by Taylor linearization:

$$
\hat{V}_p(\hat{p}) \;\dot{=}\;
\frac{\hat{V}_p(\hat{N}_1) + \hat{p}^2\,\hat{V}_p(\hat{N}_w)
- 2\hat{p}\,\widehat{\text{cov}}(\hat{N}_1, \hat{N}_w)}
{\hat{N}_w^2}.
$$

```{r}
#| label: prop-binary
r_pobre <- estimate_survey(
  design    = design,
  variable  = "pobre",
  estimator = "prop"
)
r_pobre
```

#### Multinomial Categorical Variable

For a variable with categories $\mathcal{K} = \{k_1, k_2, \ldots\}$,
the proportion for category $k$ is:

$$
\hat{p}_k =
\frac{\displaystyle\sum_{h=1}^{H}\sum_{\alpha=1}^{\alpha_h}
\sum_{i=1}^{n_{h\alpha}} \omega_{h\alpha i}\, I(y_i = k)}
{\displaystyle\sum_{h=1}^{H}\sum_{\alpha=1}^{\alpha_h}
\sum_{i=1}^{n_{h\alpha}} \omega_{h\alpha i}}
= \frac{\hat{N}_k}{\hat{N}_w}.
$$

The function automatically constructs the indicator $I(y_i = k)$ for
each category:

```{r}
#| label: prop-cat
r_empleo <- estimate_survey(
  design    = design,
  variable  = "empleo",
  estimator = "prop"
)
r_empleo
```

### Ratio Estimator

The ratio estimator of two population totals is [@cochran1977]:

$$
\hat{R} = \frac{\hat{Y}_w}{\hat{X}_w}
= \frac{\displaystyle\sum_{k \in s} w_k\, y_k}
       {\displaystyle\sum_{k \in s} w_k\, x_k}.
$$

Variance is estimated by first-order Taylor linearization:

$$
\hat{V}_p(\hat{R}) \approx
\frac{1}{\hat{X}_w^2}\,
\hat{V}_p\!\left(\hat{Y}_w - \hat{R}\,\hat{X}_w\right).
$$

**Numeric / Numeric:**

```{r}
#| label: ratio-num
r_ratio <- estimate_survey(
  design      = design,
  estimator   = "ratio",
  numerator   = "ingreso_pc",
  denominator = "gasto_pc"
)
r_ratio
```

**Categorical / Categorical** — ratio of Formal to Informal workers
($\hat{N}_{\text{Formal}} / \hat{N}_{\text{Informal}}$):

```{r}
#| label: ratio-cat
r_ratio_cat <- estimate_survey(
  design          = design,
  estimator       = "ratio",
  numerator       = "empleo",
  denominator     = "empleo",
  ratio_num_level = "Formal",
  ratio_den_level = "Informal"
)
r_ratio_cat
```

**Numeric / Categorical** — average income among formal workers,
equivalent to $\hat{Y}_{\text{income}} / \hat{N}_{\text{Formal}}$:

```{r}
#| label: ratio-mixed
r_ratio_mix <- estimate_survey(
  design          = design,
  estimator       = "ratio",
  numerator       = "ingreso_pc",
  denominator     = "empleo",
  ratio_den_level = "Formal"
)
r_ratio_mix
```

### Quantiles

Quantiles are derived from the **weighted empirical cumulative
distribution function** [@woodruff1952]:

$$
\hat{F}_w(t) =
\frac{\displaystyle\sum_{k \in s} w_k\, I(y_k \le t)}
     {\displaystyle\sum_{k \in s} w_k}
= \frac{\hat{N}(y \le t)}{\hat{N}_w}.
$$

The $p$-th order quantile is defined as:

$$
\hat{q}_p = \inf\bigl\{t : \hat{F}_w(t) \ge p\bigr\}.
$$

Confidence intervals are computed using the Woodruff linearization
method, which transforms the problem to the scale of the cumulative
proportion:

$$
IC_p[\hat{q}_p] =
\left\{t : \hat{F}_w(t) \in
\left[p \pm t_{1-\alpha/2,\,df}\; ee(\hat{F}_w(t))\right]\right\}.
$$

```{r}
#| label: quantile
r_quant <- estimate_survey(
  design    = design,
  variable  = "ingreso_pc",
  estimator = "quantile",
  probs     = c(0.10, 0.25, 0.50, 0.75, 0.90)
)
r_quant
```


## Domain Estimation

In household surveys it is common to estimate parameters for
**subpopulations** or **domains** $U_d \subset U$. The weighted ratio
estimator in domain $d$ is:

$$
\bar{y}_{w,d} =
\frac{\displaystyle\sum_{k \in s} w_k\, y_k\, I(k \in U_d)}
     {\displaystyle\sum_{k \in s} w_k\, I(k \in U_d)}
= \frac{\hat{Y}_{w,d}}{\hat{N}_{w,d}}.
$$

Variance estimation is carried out over the full sample $s$, preserving
the design structure and avoiding subsetting bias [@lumley2010].

### Domain Design Effect

The design effect for domain $d$ is defined analogously to the
overall DEFF [@kish1965]:

$$
\widehat{\text{DEFF}}_d =
\frac{\hat{V}_p(\hat{\theta}_d)}
     {\hat{V}_{\text{SRS}}(\hat{\theta}_d)},
$$

where $\hat{V}_{\text{SRS}}(\hat{\theta}_d)$ is the variance that would
be obtained under SRS restricted to domain $d$. For the domain mean,
this simplifies to:

$$
\hat{V}_{\text{SRS}}(\bar{y}_{w,d}) =
\left(1 - \frac{n_d}{N_d}\right)\frac{S_{y,d}^2}{n_d},
$$

with $n_d = \sum_{k \in s} I(k \in U_d)$ the domain sample size,
$N_d \approx \hat{N}_{w,d}$ the estimated domain population size, and
$S_{y,d}^2$ the unweighted within-domain sample variance. Values
$\widehat{\text{DEFF}}_d > 1$ indicate that clustering or unequal
weighting inflate variance even within the domain.

The `by` argument controls estimation domains:

```{r}
#| label: domain-mean
r_region <- estimate_survey(
  design    = design,
  variable  = "ingreso_pc",
  estimator = "mean",
  by        = "region"
)
r_region
```

Multiple domain variables are supported (crossed domains
$U_{d_1} \cap U_{d_2}$):

```{r}
#| label: domain-multi
r_region_area <- estimate_survey(
  design    = design,
  variable  = "ingreso_pc",
  estimator = "mean",
  by        = c("region", "area")
)
r_region_area
```

Proportions by domain:

```{r}
#| label: domain-prop
r_pobre_region <- estimate_survey(
  design    = design,
  variable  = "pobre",
  estimator = "prop",
  by        = "region"
)
r_pobre_region
```


## Formatting Results

`format_results_table()` rounds numeric columns, computes missing $CV$
or confidence intervals, and ensures the output always contains columns
`estimate`, `se`, `cv`, `lci`, and `uci`.

```{r}
#| label: format
format_results_table(r_region, digits = 3)
```


## Visualisation

`plot_results_bar()` generates a `ggplot2` bar chart with error bars
representing the confidence interval
$[\hat{\theta} - t\, ee(\hat{\theta}),\; \hat{\theta} + t\, ee(\hat{\theta})]$.
Domain variables are detected automatically as any column not in the
standard output columns.

```{r}
#| label: plot-region
#| fig.cap: "Per-capita income by region — $\\bar{y}_{w,d}$ with 95% CI"
plot_results_bar(r_region)
```

```{r}
#| label: plot-multi
#| fig.cap: "Per-capita income by region and area, 95% CI"
plot_results_bar(r_region_area)
```

Proportion plots automatically constrain the y-axis to $[0, 1]$:

```{r}
#| label: plot-prop
#| fig.cap: "Poverty rate by region — $\\hat{p}_d$ with 95% CI"
plot_results_bar(r_pobre_region)
```

---

## Shiny Application

The package includes a full interactive Shiny application covering the
complete analysis pipeline:

1. **Data** — upload CSV / RDS / XLSX or load built-in example data
2. **Survey design** — choose SRS, stratified, or multistage cluster;
   select weight $w_k$, stratum $h$, and PSU $\alpha$ variables;
   view MathJax theory
3. **Estimation** — select estimator ($\bar{y}_w$, $\hat{Y}_w$,
   $\hat{p}_k$, $\hat{R}$, $\hat{q}_p$), target variable, and domains;
   execute and inspect results with $CV$-based precision indicators

Launch the application with:

```{r}
#| label: shiny
#| eval: false
ComplexSurvey_app()
```


## Complete Workflow Example

```{r}
#| label: workflow
library(complexr)

# 1. Generate / load data
data <- generate_example_data(n_upm = 100, seed = 2024)

# 2. Derive new variables
data <- mutate_survey_data(
  data,
  definitions = list(
    log_ingreso = ~ log(ingreso_pc + 1)
  )
)

# 3. Build survey design (stratified multistage)
design <- as_survey_design_tbl(
  data    = data,
  weight  = "weight",
  strata  = "strata",
  cluster = "upm",
  nest    = TRUE
)

# 4. Diagnose: N_hat, H, PSUs, CV(w)
describe_survey_design(design)

# 5. Estimate domain mean and format
res <- estimate_survey(
  design    = design,
  variable  = "ingreso_pc",
  estimator = "mean",
  by        = c("region", "area")
)

format_results_table(res, digits = 2)
```


## References {.unnumbered}
