Basic Workflow with svySE
Luis Burgos
2026-07-13
Introduction
svySE provides a structured workflow for producing
indicator tables from complex survey data.
The package separates two complementary tasks:
svySE_calc() calculates weighted estimates and sampling
errors using sampling weights and, when available, strata and cluster
variables.
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
| 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.
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)
#> dept strata cluster service weight ind_1 ind_2
#> 1 A S1 1 S1 21.50310 0 1
#> 2 A S1 1 S2 41.53221 1 1
#> 3 A S1 1 S1 26.35908 0 0
#> 4 A S1 1 S2 45.32070 1 1
#> 5 A S1 1 S1 47.61869 0 0
#> 6 A S1 2 S2 11.82226 0 0
Calculate sampling errors
svySE_calc() calculates weighted estimates and measures
of sampling precision.
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
#> svySE sampling error result
#> --------------------------------------------------
#> Indicators : ind_1, ind_2
#> Groups : dept
#> Strata : strata
#> Cluster : cluster
#> Weight : weight
#> Division : NULL
#> Estimator : prop
#> Target : 1
#> Strict : FALSE
#> Simple tab : No (use svySE_simple())
The returned object has class "svySE_result".
class(res_error)
#> [1] "svySE_result" "list"
Results are organized by indicator and division.
names(res_error$results)
#> [1] "ind_1" "ind_2"
names(res_error$results$ind_1$error)
#> [1] "TOTAL"
The national and grouped results for the first indicator can be
inspected with:
res_error$results$ind_1$error$TOTAL
#> dept est_abs est_pct se_abs se_pct ci_l_abs ci_l_pct ci_u_abs
#> 1 NACIONAL 2274.6821 50.26904 227.0537 4.182067 1829.6650 42.07234 2719.6992
#> 2 A 760.7571 49.39397 134.7782 7.768911 496.5967 34.16719 1024.9174
#> 3 B 933.1969 64.17897 109.2721 5.617541 719.0274 53.16879 1147.3664
#> 4 C 580.7282 37.93676 146.4508 8.122624 293.6899 22.01671 867.7664
#> ci_u_pct cv deff n_unw
#> 1 58.46574 8.319368 1.0781551 72
#> 2 64.62076 15.728459 1.2665513 23
#> 3 75.18915 8.752931 0.6797495 30
#> 4 53.85680 21.410960 1.4608894 19
The sampling error table contains:
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.
| Weight only |
NULL |
NULL |
| Stratified |
Variable name |
NULL |
| Clustered |
NULL |
Variable name |
| Stratified and clustered |
Variable name |
Variable name |
Weight-only design
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
#> svySE sampling error result
#> --------------------------------------------------
#> Indicators : ind_1
#> Groups : dept
#> Strata : NULL
#> Cluster : NULL
#> Weight : weight
#> Division : NULL
#> Estimator : prop
#> Target : 1
#> Strict : FALSE
#> Simple tab : No (use svySE_simple())
Stratified design
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
#> svySE sampling error result
#> --------------------------------------------------
#> Indicators : ind_1
#> Groups : dept
#> Strata : strata
#> Cluster : NULL
#> Weight : weight
#> Division : NULL
#> Estimator : prop
#> Target : 1
#> Strict : FALSE
#> Simple tab : No (use svySE_simple())
Clustered design
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
#> svySE sampling error result
#> --------------------------------------------------
#> Indicators : ind_1
#> Groups : dept
#> Strata : NULL
#> Cluster : cluster
#> Weight : weight
#> Division : NULL
#> Estimator : prop
#> Target : 1
#> Strict : FALSE
#> Simple tab : No (use svySE_simple())
Stratified and clustered design
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
#> svySE sampling error result
#> --------------------------------------------------
#> Indicators : ind_1
#> Groups : dept
#> Strata : strata
#> Cluster : cluster
#> Weight : weight
#> Division : NULL
#> Estimator : prop
#> Target : 1
#> Strict : FALSE
#> Simple tab : No (use svySE_simple())
Domain estimation
The division argument generates separate results for
each observed category of a division variable.
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)
#> [1] "TOTAL" "S1" "S2"
The TOTAL element contains the complete estimate, while
the remaining elements contain the corresponding division results.
res_domain$results$ind_1$error$S1
#> dept est_abs est_pct se_abs se_pct ci_l_abs ci_l_pct ci_u_abs
#> 1 NACIONAL 1135.5816 50.12187 158.81289 5.725684 824.3141 38.89974 1446.8492
#> 2 A 283.6570 38.83620 81.08334 9.105621 124.7366 20.98951 442.5775
#> 3 B 568.1100 72.84501 100.44052 9.339124 371.2502 54.54066 764.9698
#> 4 C 283.8146 37.57349 92.51339 10.743894 102.4917 16.51584 465.1376
#> ci_u_pct cv deff n_unw
#> 1 61.34401 11.42352 1.0036189 35
#> 2 56.68288 23.44622 0.8612027 9
#> 3 91.14935 12.82054 1.1615982 17
#> 4 58.63113 28.59435 1.2557022 9
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.
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,
verbose = FALSE
)
res_simple
#> svySE simple result
#> --------------------------------------------------
#> Indicators : ind_1, ind_2
#> Groups : dept
#> Division : NULL
#> Target : 1
#> Weighted : No
#> Warning : Results describe the observed sample only.
The returned object has class "svySE_simple_result".
class(res_simple)
#> [1] "svySE_simple_result" "list"
A simple table can be inspected with:
res_simple$results$ind_1$simple$TOTAL
#> dept freq_0 pct_0 freq_1 pct_1 freq_total pct_total
#> 1 NACIONAL 78 52 72 48 150 100
#> 2 A 27 54 23 46 50 100
#> 3 B 20 40 30 60 50 100
#> 4 C 31 62 19 38 50 100
The table contains:
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().
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)
#> [1] "TOTAL" "S1" "S2"
Export sampling errors to XLSX
The following example writes a sampling error workbook to a temporary
file.
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)
#> [1] TRUE
Export simple tables to XLSX
file_tab <- tempfile(fileext = ".xlsx")
export_simple <- svySE_xlsx(
x = res_simple,
file_err = NULL,
file_tab = file_tab,
cols_tab = svySE_cols_tab("full"),
overwrite = TRUE
)
file.exists(file_tab)
#> [1] TRUE
Export multiple analyses
svySE_xlsx() can receive a named list containing several
result objects.
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.
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 = svySE_cols_tab("full"),
overwrite = TRUE
)
file.exists(multiple_err)
#> [1] TRUE
file.exists(multiple_tab)
#> [1] TRUE
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
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)
#> [1] TRUE
Select simple results
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)
#> [1] TRUE
Customize exported columns
Sampling error columns
The complete set of sampling error columns can be requested with:
svySE_cols_err("full")
#> [1] "est_abs" "est_pct" "se_abs" "se_pct" "ci_l_abs" "ci_l_pct"
#> [7] "ci_u_abs" "ci_u_pct" "cv" "deff" "n_unw"
A custom selection can be defined with:
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
#> [1] "est_pct" "se_pct" "ci_l_pct" "ci_u_pct" "cv" "deff" "n_unw"
Use the custom selection during export:
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)
#> [1] TRUE
Simple table columns
svySE_cols_tab("full")
#> [1] "freq_0" "pct_0" "freq_1" "pct_1" "freq_total"
#> [6] "pct_total"
A custom selection can be defined with:
simple_columns <- svySE_cols_tab(
type = "custom",
cols = c(
"freq_1",
"pct_1",
"freq_total"
)
)
simple_columns
#> [1] "freq_1" "pct_1" "freq_total"
Use the custom selection during export:
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)
#> [1] TRUE
Main functions
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.
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:
- configure sampling error estimation with
svySE_cfg();
- calculate weighted estimates and sampling errors with
svySE_calc();
- work with weight-only, stratified, clustered, and combined
designs;
- calculate domain estimates;
- generate unweighted descriptive tables with
svySE_simple();
- export sampling errors and simple tables separately;
- consolidate several analyses in one export process;
- select specific results before exporting;
- 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.