Diseños de encuestas y validación (ES)
Source:vignettes/complex-designs-es.Rmd
complex-designs-es.RmdIntroducción
Los diseños muestrales complejos requieren un tratamiento especial
para la estimación correcta de la varianza. metasurvey gestiona el
diseño muestral de forma automática mediante el objeto
Survey, de modo que el usuario pueda concentrarse en el
análisis y no en los detalles técnicos.
Esta viñeta aborda los siguientes temas:
- Creación de encuestas con distintos tipos de diseño
- Configuración de ponderadores y motores de datos
- Validación del pipeline de procesamiento
- Verificación cruzada de resultados con el paquete
survey
Configuración inicial
Utilizamos el conjunto de datos Academic Performance Index (API) del
paquete survey. Incluye versiones estratificadas, por
conglomerados y de muestreo aleatorio simple.
library(metasurvey.core)
library(survey)
library(data.table)
data(api, package = "survey")
dt_strat <- data.table(apistrat)Tipos de diseño muestral
Diseño ponderado simple
El diseño más sencillo utiliza ponderadores de probabilidad sin conglomerados ni estratificación:
svy_simple <- Survey$new(
data = dt_strat,
edition = "2000",
type = "api",
psu = NULL,
engine = "data.table",
weight = add_weight(annual = "pw")
)
cat_design(svy_simple)
#> [1] "\n Design: Not initialized (lazy initialization - will be created when needed)\n"Diseño estratificado por conglomerados
Muchas encuestas nacionales utilizan muestreo estratificado
multietápico. Se pasan strata y psu a
Survey$new():
dt_clus <- data.table(apiclus1)
svy_strat_clus <- Survey$new(
data = dt_strat,
edition = "2000",
type = "api",
psu = NULL,
strata = "stype",
engine = "data.table",
weight = add_weight(annual = "pw")
)
cat_design(svy_strat_clus)
#> [1] "\n Design: Not initialized (lazy initialization - will be created when needed)\n"Validación cruzada con el paquete survey:
design_strat <- svydesign(
id = ~1, strata = ~stype, weights = ~pw,
data = dt_strat
)
direct_strat <- svymean(~api00, design_strat)
wf_strat <- workflow(
list(svy_strat_clus),
survey::svymean(~api00, na.rm = TRUE),
estimation_type = "annual"
)
cat("Direct estimate:", round(coef(direct_strat), 2), "\n")
#> Direct estimate: 662.29
cat("Workflow estimate:", round(wf_strat$value, 2), "\n")
#> Workflow estimate: 662.29
cat("Match:", all.equal(
as.numeric(coef(direct_strat)),
wf_strat$value,
tolerance = 1e-6
), "\n")
#> Match: TRUEPara ejemplos reales de diseños estratificados por conglomerados con datos de CASEN, PNADc, ENIGH y DHS, ver el artículo de encuestas internacionales.
Inspección del diseño
# Check design type
cat_design_type(svy_simple, "annual")
#> [1] "None"
# View metadata
get_metadata(svy_simple)
#> Type: API
#> Edition: 2000
#> Periodicity: Annual
#> Engine: data.table
#> Design:
#> Design: Not initialized (lazy initialization - will be created when needed)
#>
#> Steps: None
#> Recipes: NoneMúltiples tipos de ponderadores
Muchas encuestas proporcionan distintos ponderadores según el período de análisis (por ejemplo, anual vs. mensual). metasurvey asocia etiquetas de periodicidad a columnas de ponderadores:
set.seed(42)
dt_multi <- copy(dt_strat)
dt_multi[, pw_monthly := pw * runif(.N, 0.9, 1.1)]
svy_multi <- Survey$new(
data = dt_multi,
edition = "2000",
type = "api",
psu = NULL,
engine = "data.table",
weight = add_weight(annual = "pw", monthly = "pw_monthly")
)
# Use different weight types in workflow()
annual_est <- workflow(
list(svy_multi),
survey::svymean(~api00, na.rm = TRUE),
estimation_type = "annual"
)
monthly_est <- workflow(
list(svy_multi),
survey::svymean(~api00, na.rm = TRUE),
estimation_type = "monthly"
)
cat("Annual estimate:", round(annual_est$value, 1), "\n")
#> Annual estimate: 662.3
cat("Monthly estimate:", round(monthly_est$value, 1), "\n")
#> Monthly estimate: 662.5Ponderadores de réplicas bootstrap
Para encuestas que proporcionan réplicas bootstrap (como la ECH de
Uruguay), se utiliza add_replicate() dentro de
add_weight():
# This example requires external files
svy_boot <- load_survey(
path = "data/main_survey.csv",
svy_type = "ech",
svy_edition = "2023",
svy_weight = add_weight(
annual = add_replicate(
weight_var = "pesoano",
replicate_path = "data/bootstrap_replicates.csv",
replicate_id = c("numero" = "id"),
replicate_pattern = "bsrep[0-9]+",
replicate_type = "bootstrap"
)
)
)Cuando se configuran ponderadores de réplicas,
workflow() los utiliza automáticamente para la estimación
de varianza mediante survey::svrepdesign().
Configuración del motor y el procesamiento
Motor de datos
metasurvey utiliza data.table por defecto para una
manipulación rápida de los datos:
# Current engine
get_engine()
#> [1] "data.table"
# Available engines
show_engines()
#> [1] "data.table" "tidyverse" "dplyr"Ejecución de steps y procesamiento diferido
step_compute(), step_recode() y
step_join() se ejecutan de forma eager al crearse;
step_filter() y step_validate() quedan siempre
diferidos hasta bake_steps(), porque el filtrado afecta el
diseño muestral. La configuración de procesamiento diferido solo
controla step_rename() y step_remove()
(diferidos por defecto):
# Check current setting (applies to rename/remove only)
lazy_default()
#> [1] TRUE
# Change for the session (not recommended for most workflows)
# set_lazy_processing(FALSE)Comportamiento de copia
Se puede controlar si las operaciones de steps modifican los datos in-place o trabajan sobre copias:
# Current setting
use_copy_default()
#> [1] TRUE
# In-place is faster but modifies the original
# set_use_copy(FALSE)Estimación de varianza
Varianza basada en el diseño
Estimación estándar de la varianza a partir del diseño muestral:
results <- workflow(
list(svy_simple),
survey::svymean(~api00, na.rm = TRUE),
survey::svytotal(~enroll, na.rm = TRUE),
estimation_type = "annual"
)
results
#> stat variable value se cv
#> <char> <char> <num> <num> <num>
#> 1: survey::svymean: api00 api00 662.2874 9.585429e+00 0.01447322
#> 2: survey::svytotal: enroll enroll 3687177.5324 1.645323e+05 0.04462283
#> confint_lower confint_upper evaluate
#> <num> <num> <char>
#> 1: 643.5003 681.0745 Excellent
#> 2: 3364700.1537 4009654.9112 ExcellentEstimación por dominios
Se pueden calcular estimaciones para subpoblaciones con
survey::svyby():
domain_results <- workflow(
list(svy_simple),
survey::svyby(~api00, ~stype, survey::svymean, na.rm = TRUE),
estimation_type = "annual"
)
domain_results
#> stat variable value se cv confint_lower
#> <char> <char> <num> <num> <num> <num>
#> 1: survey::svyby: api00 api00 674.43 12.49343 0.01852443 649.9433
#> 2: survey::svyby: api00 api00 625.82 15.34078 0.02451309 595.7526
#> 3: survey::svyby: api00 api00 636.60 16.50239 0.02592270 604.2559
#> confint_upper evaluate stype
#> <num> <char> <fctr>
#> 1: 698.9167 Excellent E
#> 2: 655.8874 Excellent H
#> 3: 668.9441 Excellent MRazones
ratio_result <- workflow(
list(svy_simple),
survey::svyratio(~api00, ~api99),
estimation_type = "annual"
)
ratio_result
#> stat variable denominator value se
#> <char> <char> <char> <num> <num>
#> 1: survey::svyratio: api00/api99 api00 api99 1.052261 0.00379243
#> cv confint_lower confint_upper evaluate
#> <num> <num> <num> <char>
#> 1: 0.003604079 1.044828 1.059694 ExcellentValidación del pipeline
Verificación paso a paso
Al construir pipelines complejos, conviene verificar cada paso de forma independiente:
# Step 1: Compute new variable
svy_v <- step_compute(svy_simple,
api_diff = api00 - api99,
comment = "API score difference"
)
# The compute already executed; the step is recorded in the pipeline
steps <- get_steps(svy_v)
cat("Recorded steps:", length(steps), "\n")
#> Recorded steps: 1Validación cruzada con el paquete survey
Se pueden comparar los resultados de workflow() de
metasurvey con llamadas directas al paquete survey:
# Method 1: Direct survey package
design <- svydesign(id = ~1, weights = ~pw, data = dt_strat)
direct_mean <- svymean(~api00, design)
# Method 2: metasurvey workflow
wf_result <- workflow(
list(svy_simple),
survey::svymean(~api00, na.rm = TRUE),
estimation_type = "annual"
)
cat("Direct estimate:", round(coef(direct_mean), 2), "\n")
#> Direct estimate: 662.29
cat("Workflow estimate:", round(wf_result$value, 2), "\n")
#> Workflow estimate: 662.29
cat("Match:", all.equal(
as.numeric(coef(direct_mean)),
wf_result$value,
tolerance = 1e-6
), "\n")
#> Match: TRUEVisualización del pipeline
Con view_graph() se puede visualizar el grafo de
dependencias entre steps:
# Requires the visNetwork package
svy_viz <- step_compute(svy_simple,
api_diff = api00 - api99,
high_growth = as.integer(api00 - api99 > 50)
)
view_graph(svy_viz, init_step = "Load API data")El DAG interactivo no se renderiza en esta vignette para reducir el tamaño del paquete; puede explorarse ejecutando el código anterior en una sesión interactiva de R.
Evaluación de calidad
Se puede evaluar la calidad de las estimaciones a partir del coeficiente de variación:
results_quality <- workflow(
list(svy_simple),
survey::svymean(~api00, na.rm = TRUE),
survey::svymean(~enroll, na.rm = TRUE),
estimation_type = "annual"
)
for (i in seq_len(nrow(results_quality))) {
cv_pct <- results_quality$cv[i] * 100
cat(
results_quality$stat[i], ":",
round(cv_pct, 1), "% CV -",
evaluate_cv(cv_pct), "\n"
)
}
#> survey::svymean: api00 : 1.4 % CV - Excellent
#> survey::svymean: enroll : 4.5 % CV - ExcellentValidación de recipes
Se puede verificar que los recipes y sus steps sean consistentes:
# Create steps and recipe
svy_rt <- step_compute(svy_simple, api_diff = api00 - api99)
my_recipe <- steps_to_recipe(
name = "API Test",
user = "QA Team",
svy = svy_rt,
description = "Recipe for validation",
steps = get_steps(svy_rt)
)
# Check documentation is correct
doc <- my_recipe$doc()
cat("Input variables:", toString(doc$input_variables), "\n")
#> Input variables: api00, api99
cat("Output variables:", toString(doc$output_variables), "\n")
#> Output variables: api_diff
# Validate against the survey
my_recipe$validate(svy_rt)
#> [1] TRUELista de verificación para validación
Antes de poner en producción un pipeline de procesamiento de encuestas, se recomienda verificar lo siguiente:
- Integridad de los datos – cantidad de filas, nombres de columnas y tipos de datos después de cada step
- Validación de ponderadores – las columnas de ponderadores existen y son positivas
- Verificación del diseño – el diseño muestral coincide con la especificación esperada (PSU, estratos, ponderadores)
- Reproducibilidad del recipe – guardar y recargar recipes, verificar el round-trip en JSON
-
Validación cruzada – comparar estimaciones clave
con valores publicados o llamadas directas al paquete
survey - Umbrales de CV – señalar estimaciones con coeficientes de variación elevados
validate_pipeline <- function(svy) {
data <- get_data(svy)
checks <- list(
has_data = !is.null(data),
has_rows = nrow(data) > 0,
has_weights = all(
unlist(svy$weight)[is.character(unlist(svy$weight))] %in% names(data)
)
)
passed <- all(unlist(checks))
if (passed) {
message("All validation checks passed")
} else {
failed <- names(checks)[!unlist(checks)]
warning("Failed checks: ", toString(failed))
}
invisible(checks)
}
validate_pipeline(svy_simple)Buenas prácticas
- Utilizar siempre los ponderadores adecuados – nunca calcular estadísticos sin ponderar a partir de datos de encuestas
- Usar ponderadores de réplicas cuando estén disponibles – proporcionan estimaciones de varianza más robustas
- Verificar los tamaños de muestra por dominio – combinar dominios pequeños cuando los CV sean demasiado altos
- Documentar el diseño – incluir la especificación del diseño, la construcción de los ponderadores y el método de varianza
- Hacer validación cruzada de las estimaciones clave – comparar con valores publicados o métodos alternativos
Próximos pasos
-
Flujos de
estimación –
workflow(),RecipeWorkflowy estimaciones publicables -
Paneles rotativos y
PoolSurvey – Análisis longitudinal con
RotativePanelSurveyyPoolSurvey