---
title: "Basic Workflow with svySE"
author: "Luis Burgos"
date: "`r Sys.Date()`"
output:
  rmarkdown::html_vignette:
    toc: true
    toc_depth: 2
vignette: >
  %\VignetteIndexEntry{Basic Workflow with svySE}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

# Introduction

`svySE` provides a structured workflow for producing indicator tables from
complex survey data.

The package separates two complementary tasks:

1. `svySE_calc()` calculates weighted estimates and sampling errors using
   sampling weights and, when available, strata and cluster variables.
2. `svySE_simple()` calculates unweighted frequencies and percentages from the
   observed sample without using the survey design.

Results generated by either function can be exported to `.xlsx` files with
`svySE_xlsx()`. The export function can process one result or consolidate
several analyses generated from different datasets, indicators, weights, or
function calls.

The package is built on top of `survey` for design-based estimation and uses
`openxlsx` for workbook generation.

# Package workflow

| Step | Function | Purpose |
|------|----------|---------|
| 1 | `svySE_cfg()` | Configure estimation options |
| 2A | `svySE_calc()` | Calculate weighted estimates and sampling errors |
| 2B | `svySE_simple()` | Calculate unweighted frequencies and percentages |
| 3 | `svySE_xlsx()` | Export one or multiple results to `.xlsx` files |

The two calculation functions are intentionally separated. This avoids
performing unnecessary calculations when only sampling errors or only
descriptive tables are required.

# Example data

The following simulated dataset contains:

- one grouping variable;
- one stratification variable;
- one cluster variable;
- one sampling weight;
- one division variable;
- two binary indicators.

```{r example-data}
library(svySE)

set.seed(123)

df <- data.frame(
  dept = rep(c("A", "B", "C"), each = 50),
  strata = rep(c("S1", "S2", "S3"), each = 50),
  cluster = rep(seq_len(30), each = 5),
  service = rep(c("S1", "S2"), length.out = 150),
  weight = runif(150, 10, 50),
  ind_1 = sample(c(0, 1), 150, replace = TRUE),
  ind_2 = sample(c(0, 1), 150, replace = TRUE),
  stringsAsFactors = FALSE
)

head(df)
```

# Configure sampling error estimation

`svySE_cfg()` defines the settings used by `svySE_calc()`.

```{r configuration}
cfg <- svySE_cfg(
  estimator = "prop",
  variance = "taylor",
  lonely_psu = "adjust",
  conf_level = 0.95,
  target = 1,
  valid_values = c(0, 1),
  truncate_lower_ci = TRUE,
  pct_mult = 100,
  deff = TRUE,
  cv = TRUE,
  na_rm = TRUE
)

cfg
```

The principal options are:

| Argument | Purpose |
|----------|---------|
| `estimator` | Selects the estimator used in the analysis |
| `variance` | Defines the variance estimation method |
| `lonely_psu` | Specifies how strata containing one PSU are handled |
| `conf_level` | Defines the confidence level |
| `target` | Identifies the indicator category of interest |
| `valid_values` | Defines the valid indicator values |
| `truncate_lower_ci` | Truncates negative lower confidence limits at zero |
| `pct_mult` | Converts proportions to the selected percentage scale |
| `deff` | Enables or disables design-effect calculation |
| `cv` | Enables or disables coefficient-of-variation calculation |
| `na_rm` | Controls the treatment of missing values |

# Calculate sampling errors

`svySE_calc()` calculates weighted estimates and measures of sampling
precision.

```{r sampling-errors}
res_error <- svySE_calc(
  data = df,
  indicators = c("ind_1", "ind_2"),
  group_vars = "dept",
  group_labels = "Department",
  strata = "strata",
  cluster = "cluster",
  weight = "weight",
  division = NULL,
  div_weight = NULL,
  cfg = cfg,
  verbose = FALSE
)

res_error
```

The returned object has class `"svySE_result"`.

```{r sampling-error-class}
class(res_error)
```

Results are organized by indicator and division.

```{r inspect-error-object}
names(res_error$results)
names(res_error$results$ind_1$error)
```

The national and grouped results for the first indicator can be inspected with:

```{r inspect-error-table}
res_error$results$ind_1$error$TOTAL
```

The sampling error table contains:

| Column | Description |
|--------|-------------|
| `est_abs` | Weighted absolute estimate |
| `est_pct` | Weighted percentage estimate |
| `se_abs` | Standard error of the absolute estimate |
| `se_pct` | Standard error of the percentage |
| `ci_l_abs` | Lower confidence limit for the absolute estimate |
| `ci_l_pct` | Lower confidence limit for the percentage |
| `ci_u_abs` | Upper confidence limit for the absolute estimate |
| `ci_u_pct` | Upper confidence limit for the percentage |
| `cv` | Coefficient of variation |
| `deff` | Design effect |
| `n_unw` | Unweighted number of target cases |

# Supported survey designs

`svySE_calc()` can be used with different combinations of design variables.

| Design | `strata` | `cluster` |
|--------|----------|-----------|
| Weight only | `NULL` | `NULL` |
| Stratified | Variable name | `NULL` |
| Clustered | `NULL` | Variable name |
| Stratified and clustered | Variable name | Variable name |

## Weight-only design

```{r design-weight-only}
res_weight <- svySE_calc(
  data = df,
  indicators = "ind_1",
  group_vars = "dept",
  group_labels = "Department",
  strata = NULL,
  cluster = NULL,
  weight = "weight",
  cfg = cfg,
  verbose = FALSE
)

res_weight
```

## Stratified design

```{r design-stratified}
res_strata <- svySE_calc(
  data = df,
  indicators = "ind_1",
  group_vars = "dept",
  group_labels = "Department",
  strata = "strata",
  cluster = NULL,
  weight = "weight",
  cfg = cfg,
  verbose = FALSE
)

res_strata
```

## Clustered design

```{r design-clustered}
res_cluster <- svySE_calc(
  data = df,
  indicators = "ind_1",
  group_vars = "dept",
  group_labels = "Department",
  strata = NULL,
  cluster = "cluster",
  weight = "weight",
  cfg = cfg,
  verbose = FALSE
)

res_cluster
```

## Stratified and clustered design

```{r design-complex}
res_complex <- svySE_calc(
  data = df,
  indicators = "ind_1",
  group_vars = "dept",
  group_labels = "Department",
  strata = "strata",
  cluster = "cluster",
  weight = "weight",
  cfg = cfg,
  verbose = FALSE
)

res_complex
```

# Domain estimation

The `division` argument generates separate results for each observed category
of a division variable.

```{r domain-estimation}
res_domain <- svySE_calc(
  data = df,
  indicators = "ind_1",
  group_vars = "dept",
  group_labels = "Department",
  strata = "strata",
  cluster = "cluster",
  weight = "weight",
  division = "service",
  div_weight = NULL,
  cfg = cfg,
  verbose = FALSE
)

names(res_domain$results$ind_1$error)
```

The `TOTAL` element contains the complete estimate, while the remaining
elements contain the corresponding division results.

```{r inspect-domain}
res_domain$results$ind_1$error$S1
```

When a division requires a different expansion factor, it can be provided
through `div_weight`.

# Calculate simple indicator tables

`svySE_simple()` calculates unweighted frequencies and percentages without
requiring sampling weights, strata, or clusters.

```{r simple-tables}
res_simple <- svySE_simple(
  data = df,
  indicators = c("ind_1", "ind_2"),
  group_vars = "dept",
  group_labels = "Department",
  division = NULL,
  target = 1,
  valid_values = c(0, 1),
  pct_mult = 100,
  na_rm = TRUE,
  verbose = FALSE
)

res_simple
```

# Missing values in simple indicator tables

`svySE_simple()` provides explicit control over missing indicator values through
the `na_rm` argument.

When `na_rm = TRUE`, missing values are removed before frequencies and
percentages are calculated.

```{r simple-missing-values}
df_missing <- data.frame(
  dept = c("A", "A", "B", "B", "C", "C"),
  ind_1 = c(1, 0, NA, NA, 1, 1)
)

res_missing <- svySE_simple(
  data = df_missing,
  indicators = "ind_1",
  group_vars = "dept",
  group_labels = "Department",
  na_rm = TRUE,
  verbose = FALSE
)

res_missing$results$ind_1$simple$TOTAL
```

Department `B` is omitted because it does not contain any valid observations
for `ind_1`.

Missing observations are also excluded from the national denominator.

When `na_rm = FALSE`, missing indicator values are treated as a validation
condition and the calculation stops.

```{r simple-missing-error, error=TRUE}
svySE_simple(
  data = df_missing,
  indicators = "ind_1",
  group_vars = "dept",
  na_rm = FALSE,
  verbose = FALSE
)
```

This behavior makes the treatment of missing indicator values explicit and
prevents missing observations from being silently included in the denominator.

The returned object has class `"svySE_simple_result"`.

```{r simple-class}
class(res_simple)
```

A simple table can be inspected with:

```{r inspect-simple}
res_simple$results$ind_1$simple$TOTAL
```

The table contains:

| Column | Description |
|--------|-------------|
| `freq_0` | Frequency of non-target cases |
| `pct_0` | Percentage of non-target cases |
| `freq_1` | Frequency of target cases |
| `pct_1` | Percentage of target cases |
| `freq_total` | Total number of valid observations |
| `pct_total` | Total percentage |

The results generated by `svySE_simple()` describe the observed sample only.
Because no sampling weights or design variables are used, these percentages
should not be interpreted as population estimates.

# Simple tables by division

A division variable can also be used with `svySE_simple()`.

```{r simple-domain}
res_simple_domain <- svySE_simple(
  data = df,
  indicators = "ind_1",
  group_vars = "dept",
  group_labels = "Department",
  division = "service",
  target = 1,
  valid_values = c(0, 1),
  pct_mult = 100,
  verbose = FALSE
)

names(res_simple_domain$results$ind_1$simple)
```

# Export sampling errors to XLSX

The following example writes a sampling error workbook to a temporary file.

```{r export-error}
file_err <- tempfile(fileext = ".xlsx")

export_error <- svySE_xlsx(
  x = res_error,
  file_err = file_err,
  file_tab = NULL,
  cols_err = svySE_cols_err("full"),
  overwrite = TRUE
)

file.exists(file_err)
```

# Export simple tables to XLSX

```{r export-simple}
file_tab <- tempfile(fileext = ".xlsx")

export_simple <- svySE_xlsx(
  x = res_simple,
  file_err = NULL,
  file_tab = file_tab,
  cols_tab = NULL,
  overwrite = TRUE
)

file.exists(file_tab)
```

# Export multiple analyses

`svySE_xlsx()` can receive a named list containing several result objects.

```{r multiple-results}
results <- list(
  Main_errors = res_error,
  Domain_errors = res_domain,
  Main_simple = res_simple,
  Domain_simple = res_simple_domain
)
```

The function automatically identifies the class of each object:

- `"svySE_result"` objects are exported to `file_err`;
- `"svySE_simple_result"` objects are exported to `file_tab`.

```{r export-multiple}
multiple_err <- tempfile(fileext = ".xlsx")
multiple_tab <- tempfile(fileext = ".xlsx")

export_multiple <- svySE_xlsx(
  x = results,
  file_err = multiple_err,
  file_tab = multiple_tab,
  cols_err = svySE_cols_err("full"),
  cols_tab = NULL,
  overwrite = TRUE
)

file.exists(multiple_err)
file.exists(multiple_tab)
```

This is useful when several indicators are calculated from different datasets,
survey weights, domains, or analytical processes.

# Export selected results

The `select` argument restricts the export to chosen elements of a named list.

## Select sampling error results

```{r select-errors}
selected_err <- tempfile(fileext = ".xlsx")

svySE_xlsx(
  x = results,
  select = c("Main_errors", "Domain_errors"),
  file_err = selected_err,
  file_tab = NULL,
  overwrite = TRUE
)

file.exists(selected_err)
```

## Select simple results

```{r select-simple}
selected_tab <- tempfile(fileext = ".xlsx")

svySE_xlsx(
  x = results,
  select = c("Main_simple", "Domain_simple"),
  file_err = NULL,
  file_tab = selected_tab,
  overwrite = TRUE
)

file.exists(selected_tab)
```

# Customize exported columns

## Sampling error columns

The complete set of sampling error columns can be requested with:

```{r error-columns-full}
svySE_cols_err("full")
```

A custom selection can be defined with:

```{r error-columns-custom}
error_columns <- svySE_cols_err(
  type = "custom",
  cols = c(
    "est_pct",
    "se_pct",
    "ci_l_pct",
    "ci_u_pct",
    "cv",
    "deff",
    "n_unw"
  )
)

error_columns
```

Use the custom selection during export:

```{r export-custom-errors}
custom_err <- tempfile(fileext = ".xlsx")

svySE_xlsx(
  x = res_error,
  file_err = custom_err,
  file_tab = NULL,
  cols_err = error_columns,
  overwrite = TRUE
)

file.exists(custom_err)
```

## Simple table columns

```{r simple-columns-full}
svySE_cols_tab("full")
```

A custom selection can be defined with:

```{r simple-columns-custom}
simple_columns <- svySE_cols_tab(
  type = "custom",
  cols = c(
    "freq_1",
    "pct_1",
    "freq_total"
  )
)

simple_columns
```

Use the custom selection during export:

```{r export-custom-simple}
custom_tab <- tempfile(fileext = ".xlsx")

svySE_xlsx(
  x = res_simple,
  file_err = NULL,
  file_tab = custom_tab,
  cols_tab = simple_columns,
  overwrite = TRUE
)

file.exists(custom_tab)
```

# Main functions

| Function | Description |
|----------|-------------|
| `svySE_cfg()` | Configure sampling error estimation |
| `svySE_calc()` | Calculate weighted estimates and sampling errors |
| `svySE_simple()` | Calculate unweighted frequencies and percentages |
| `svySE_xlsx()` | Export one or multiple results to `.xlsx` files |
| `svySE_cols_err()` | Select sampling error columns |
| `svySE_cols_tab()` | Select simple table columns |

# Technical foundation

`svySE` uses established R packages for its internal workflow.

| Package | Role |
|---------|------|
| `survey` | Design-based estimation and variance calculation |
| `openxlsx` | Creation and formatting of `.xlsx` workbooks |
| `stats` | Statistical formulas, coefficients, and confidence intervals |
| `svySE` | High-level workflow for indicators, sampling errors, tables, and export |

`svySE` does not replace `survey`. It provides a structured interface for
repeated indicator production, quality measurement, and export.

# Summary

This vignette demonstrated how to:

1. configure sampling error estimation with `svySE_cfg()`;
2. calculate weighted estimates and sampling errors with `svySE_calc()`;
3. work with weight-only, stratified, clustered, and combined designs;
4. calculate domain estimates;
5. generate unweighted descriptive tables with `svySE_simple()`;
6. export sampling errors and simple tables separately;
7. consolidate several analyses in one export process;
8. select specific results before exporting;
9. customize the columns included in `.xlsx` files.

The same workflow can be applied to official survey datasets by specifying the
corresponding indicators, grouping variables, weights, strata, and clusters.

## Exporting simple-table column profiles

When `cols_tab = NULL`, `svySE_xlsx()` exports all simple-table columns actually
available in each result object:

```{r, eval=FALSE}
svySE_xlsx(
  x = res_both,
  file_tab = "simple_all.xlsx",
  cols_tab = NULL
)
```

Predefined profiles are available:

```{r}
svySE_cols_tab("unweighted")
svySE_cols_tab("freq")
svySE_cols_tab("pct")
svySE_cols_tab("expanded")
svySE_cols_tab("expanded_freq")
svySE_cols_tab("expanded_pct")
svySE_cols_tab("counts")
svySE_cols_tab("percentages")
```

For example, export only sample and expanded counts:

```{r, eval=FALSE}
svySE_xlsx(
  x = res_both,
  file_tab = "simple_counts.xlsx",
  cols_tab = svySE_cols_tab("counts")
)
```

A fully custom selection is also supported:

```{r, eval=FALSE}
custom_columns <- svySE_cols_tab(
  type = "custom",
  cols = c(
    "freq_1",
    "pct_1",
    "exp_1",
    "exp_pct_1",
    "freq_total",
    "exp_total",
    "exp_pct_total"
  )
)

svySE_xlsx(
  x = res_both,
  file_tab = "simple_custom.xlsx",
  cols_tab = custom_columns
)
```

The requested columns must exist in the calculated object. For example,
expanded columns require `output = "weighted"` or `output = "both"`.

