La segregación ocupacional por género es un fenómeno estructural que concentra a mujeres y hombres en diferentes ocupaciones y sectores, reproduciendo desigualdades que limitan oportunidades, perpetúan brechas salariales y restringen el desarrollo del capital humano. El Índice de Disimilitud (ID) de Nuevo León es 0.539, lo que refleja un nivel alto de segregación. Según García, Hernández y Rivera (2018), el estado se ubica entre los más segregados del país, solo detrás de Oaxaca, Veracruz e Hidalgo, y más segregado que Baja California, Ciudad de México o Tamaulipas. Los centros comunitarios son agentes clave en la capacitación laboral, pero si no se diseñan con perspectiva de género pueden reproducir la segregación. Talleres “feminizados” y “masculinizados” refuerzan estereotipos y mantienen la brecha salarial, ya que los oficios asociados a mujeres suelen tener menores ingresos y mayor informalidad. La interseccionalidad agrava el problema: ser mujer, vivir en pobreza, tener bajo nivel educativo o ciertas condiciones familiares genera múltiples barreras. En Nuevo León, 31% de las personas en pobreza tienen secundaria incompleta o menos (2022), y los CDSC son su principal o única vía de capacitación. Aunque la Ley de Desarrollo Social de Nuevo León y el Plan Estatal de Desarrollo 2022–2027 promueven la igualdad de género y el trabajo decente (ODS 5 y 8), los programas sin enfoque inclusivo pueden excluir a mujeres de oficios técnicos y reproducir desigualdades. Los resultados cuantitativos reflejan un escenario positivo y satisfactorio entre las personas usuarias de los centros comunitarios. No obstante, se identifica la necesidad de mejorar la cantidad y calidad de los materiales empleados durante las capacitaciones. En los hallazgos cualitativos, se observa un interés equilibrado entre oficios tradicionales, capacitación técnica y desarrollo personal. Los participantes buscan talleres prácticos y útiles para el autoempleo, que les permitan adquirir habilidades aplicables a la vida cotidiana o al ámbito laboral. También se destaca una creciente demanda por cursos de idiomas y tecnología. La participación en los cursos es principalmente femenina (88%), conformada por mujeres adultas, en su mayoría casadas. Predomina un nivel educativo medio, con estudios de secundaria y preparatoria, y una alta proporción de mujeres que se dedican al hogar, aunque también hay trabajadoras y estudiantes. Los talleres más cursados son los de Belleza, Zumba, Corte y Confección, Gimnasia y Piñatas, impartidos sobre todo en los centros de San Bernabé, Monte Kristal, Santa Fe y La Alianza. Estos resultados reflejan tanto el interés por oficios tradicionales como la oportunidad de diversificar la oferta formativa hacia áreas técnicas y con mayor potencial de empleabilidad.
Pregunta de investigación:
¿De qué manera el género, estado civil, nivel de escolaridad y ocupación actual de los participantes en talleres influyen en su elección del taller cursado y cómo se vincula esta elección con la segregación ocupacional por género observada en los Centros Comunitarios de Nuevo León desde 2017-2025?
Realizamos la consolidación, limpieza y análisis descriptivo de bases de datos provenientes de encuestas aplicadas en centros comunitarios del estado de Nuevo León. Utilizamos diversas librerías de R (tidyverse, readxl, janitor, entre otras) para automatizar la lectura y estandarización de los archivos en formato Excel.
Cada base fue procesada para extraer el año y trimestre de su nombre, incorporando esta información en una nueva variable denominada anio_trimestre. Asimismo, se homogenizaron los nombres de las variables y se unificaron todos los archivos en un solo conjunto de datos. Posteriormente, estandarizamos las variables categóricas tipo “Sí” y “No” a formato numérico binario, filtramos los registros para conservar únicamente los centros comunitarios ubicados en Nuevo León y corregimos los formatos de texto y numéricos para garantizar la consistencia de la información.
Con la base depurada, generamos estadísticas descriptivas globales y por periodo, incluyendo conteos de registros, medias, desviaciones estándar y distribuciones de frecuencia para variables categóricas. También identificamos y exportamos las respuestas abiertas a archivos independientes, permitiendo su análisis cualitativo posterior.
Guardamos la base unificada y los distintos productos derivados en formatos CSV y RDS dentro de una carpeta de resultados. Este proceso nos permitió disponer de una base consolidada, estandarizada y lista para análisis comparativos y estudios adicionales sobre el desempeño de los centros comunitarios en el estado.
# LIBRERÍAS
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.1 ✔ stringr 1.5.2
## ✔ ggplot2 4.0.0 ✔ tibble 3.3.0
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.1.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(readxl)
library(janitor)
##
## Attaching package: 'janitor'
##
## The following objects are masked from 'package:stats':
##
## chisq.test, fisher.test
library(stringr)
library(purrr)
library(skimr)
library(dplyr)
library(knitr)
options(readr.show_col_types = FALSE)
# CARGA DE BASES DE DATOS
path_dir <- "C:/Users/tds1301/Desktop/Ciencia2" #Para poner la dirección a la carpeta donde están las bases
# Lista todos los Excel (xlsx/xls) en la carpeta y subcarpetas
xls_files <- list.files(path_dir, pattern = "\\.xlsx$|\\.xls$", recursive = TRUE, full.names = TRUE)
if (length(xls_files) == 0) stop("No se encontraron archivos Excel en la carpeta indicada.")
# UNIFICACIÓN EN UN DATAFRAME
# Creación de columna anio_trimestre
# Este código obtiene la información del año y trimestre del nombre de las bases de datos
get_anio_trimestre <- function(file_path) {
fname <- basename(file_path)
# Esta parte detecta al año (4 dígitos)
anio <- str_extract(fname, "(?<!\\d)\\d{4}(?!\\d)")
# Esta parte detecta al trimestre (Q1|Q2|Q3|Q4 o T1|T2|T3|T4 o 1T|2T|3T|4T)
tri_raw <- str_extract(fname, "(Q[1-4]|T[1-4]|[1-4]T)")
if (!is.na(tri_raw)) {
tri <- str_replace_all(tri_raw, c("^T" = "Q", "T$" = "")) # T1 -> Q1; 1T -> Q1 (simplificación)
tri <- str_replace(tri, "([1-4])T", "Q\\1")
} else {
# Si no detecta el trimestre, que busque un dígito entre 1-4 cercano a 'trim' o 'tri'
tri <- str_extract(str_to_lower(fname), "tri?m?[^0-9]*([1-4])")
tri <- if (!is.na(tri)) paste0("Q", str_extract(tri, "[1-4]")) else NA_character_
}
paste0(anio %||% "NA", "_", tri %||% "Q?")
} # Para pegar el año extraído seguido de un guión y luego el trimestre para la columna anio_trimestre
# Convertir variables a numéricas o categóricas según corresponda
read_one_excel <- function(f) {
readxl::read_excel(f, col_types = "text", guess_max = 10000) |> # Lee el excel
janitor::clean_names() |> # Limpia los nombres para evitar espacios o caracteres especiales
dplyr::mutate(
anio_trimestre = get_anio_trimestre(f), # Agrega la variable anio_trimestre antes creada
source_file = basename(f), #Agrega una columna con el nombre original de las bases de datos
)
}
# Para unir todos los archivos
df_all <- purrr::map_dfr(xls_files, read_one_excel)
## New names:
## New names:
## New names:
## New names:
## New names:
## • `Calidad de la información brindada por el personal del Centro Comunitario`
## -> `Calidad de la información brindada por el personal del Centro
## Comunitario...27`
## • `Calidad de la información brindada por el personal del Centro Comunitario`
## -> `Calidad de la información brindada por el personal del Centro
## Comunitario...28`
## • `Favor de justificar su respuesta` -> `Favor de justificar su respuesta...44`
## • `Favor de justificar su respuesta` -> `Favor de justificar su respuesta...46`
## • `Indique el por qué de su respuesta` -> `Indique el por qué de su
## respuesta...49`
## • `Indique el por qué de su respuesta` -> `Indique el por qué de su
## respuesta...51`
# Para convertir variables específicas a numéricas o categóricas dependiendo de lo que son
df_all <- df_all %>%
mutate(privacidad = as.character(horario_de_inicio_de_taller))
df_all <- df_all %>%
mutate(
# Convertir a numérica (1 = "Sí", 0 = "No")
esta_de_acuerdo_con_el_aviso_de_privacidad = case_when(
esta_de_acuerdo_con_el_aviso_de_privacidad == "Sí" ~ 1,
esta_de_acuerdo_con_el_aviso_de_privacidad == "No" ~ 0,
TRUE ~ NA_real_ # Si hay otros valores, los convertimos a NA
),
x1_el_tramite_del_curso_al_que_se_inscribio_fue_gratuito = case_when(
x1_el_tramite_del_curso_al_que_se_inscribio_fue_gratuito == "Sí" ~ 1,
x1_el_tramite_del_curso_al_que_se_inscribio_fue_gratuito == "No" ~ 0,
TRUE ~ NA_real_
),
ha_visitado_el_centro_comunitario_durante_los_ultimos_dos_meses = case_when(
ha_visitado_el_centro_comunitario_durante_los_ultimos_dos_meses == "Sí" ~ 1,
ha_visitado_el_centro_comunitario_durante_los_ultimos_dos_meses == "No" ~ 0,
TRUE ~ NA_real_
),
x4_considera_que_las_instalaciones_del_centro_comunitario_son_accesibles_para_personas_con_discapacidad = case_when(
x4_considera_que_las_instalaciones_del_centro_comunitario_son_accesibles_para_personas_con_discapacidad == "Sí" ~ 1,
x4_considera_que_las_instalaciones_del_centro_comunitario_son_accesibles_para_personas_con_discapacidad == "No" ~ 0,
TRUE ~ NA_real_
),
x5_considera_que_lo_aprendido_en_el_curso_taller_le_sera_de_utilidad = case_when(
x5_considera_que_lo_aprendido_en_el_curso_taller_le_sera_de_utilidad == "Sí" ~ 1,
x5_considera_que_lo_aprendido_en_el_curso_taller_le_sera_de_utilidad == "No" ~ 0,
TRUE ~ NA_real_
),
x7_recomendaria_a_otras_personas_este_curso_o_taller = case_when(
x7_recomendaria_a_otras_personas_este_curso_o_taller == "Sí" ~ 1,
x7_recomendaria_a_otras_personas_este_curso_o_taller == "No" ~ 0,
TRUE ~ NA_real_
),
x8_estaria_interesado_a_en_tomar_otro_curso_taller_en_este_centro_comunitario = case_when(
x8_estaria_interesado_a_en_tomar_otro_curso_taller_en_este_centro_comunitario == "Sí" ~ 1,
x8_estaria_interesado_a_en_tomar_otro_curso_taller_en_este_centro_comunitario == "No" ~ 0,
TRUE ~ NA_real_
))
# Unir bases de datos para Nuevo León
# Lista de centros comunitarios de Nuevo León
centros_nuevo_leon <- c(
"ALLENDE", "CERRALVO", "PRADOS DE SANTA ROSA", "SANTA FE", "CHINA", "EL CARMEN",
"BUSTAMANTE", "ALIANZA REAL", "EULALIO VILLARREAL", "FERNANDO AMILPA", "CADEREYTA",
"GALEANA", "TIERRA PROPIA", "VALLE SOLEADO", "GENERAL TERAN", "ZUAZUA", "HIGUERAS",
"ARBOLEDAS DE LOS NARANJOS", "LAS SABINAS", "UNIDAD PILOTO", "LOS ENCINOS",
"MONTE KRISTAL", "EL MIRADOR", "HECTOR CABALLERO", "ALIANZA SECTOR Q", "LINARES",
"LINARES LIBERTAD", "LA ALIANZA", "LOMA CHIQUITA", "RENE ALVAREZ", "SAN BERNABE",
"MONTEMORELOS", "TOPO CHICO", "PESQUERIA", "VALLE DE LA ESPERANZA",
"ALFONSO MARTINEZ DOMINGUEZ", "SABINAS HIDALGO", "INDEPENDENCIA", "LA ESTANZUELA",
"REVOLUCION PROLETARIA", "SIERRA VENTANA", "SALINAS VICTORIA"
)
# Convierte a mayúsculas los nombres de los centros comunitarios por si vienen en minúsculas o mixto
df_all <- df_all |>
mutate(centro_comunitario = str_to_upper(centro_comunitario)) |>
filter(centro_comunitario %in% centros_nuevo_leon) #Deja sólo los datos para Nuevo León
# Limpia vacíos y cambia decimal_mark si usas coma
df_all <- df_all |>
# Cambia vacíos a NA solo en las columnas de texto
dplyr::mutate(across(where(is.character), ~na_if(.x, ""))) |>
# Convierte correctamente los tipos de datos, pero sin alterar las columnas numéricas
readr::type_convert(locale = readr::locale(decimal_mark = ".")) # Esto se usa para las columnas numéricas y de fecha
##
## ── Column specification ────────────────────────────────────────────────────────
## cols(
## .default = col_character(),
## marca_temporal = col_double(),
## fecha_en_que_se_aplica_la_encuesta = col_logical(),
## x2_cuantos_anos_cumplidos_tiene = col_double(),
## horario_de_inicio_de_taller = col_double(),
## x1_1_en_caso_de_haber_respondido_no_en_la_pregunta_anterior_favor_de_responder_el_costo_del_tramite_de_inscripcion = col_double(),
## el_contenido_o_temas_del_curso_taller = col_double(),
## la_cantidad_y_calidad_de_materiales_y_equipo_utilizados_en_el_curso_taller = col_double(),
## los_horarios_del_curso_taller = col_double(),
## el_conocimiento_del_tallerista_o_instructor_sobre_el_tema_del_curso_taller = col_double(),
## la_forma_de_ensenanza_utilizada_en_las_clases = col_double(),
## la_motivacion_a_la_participacion_de_parte_del_tallerista_o_instructor = col_double(),
## el_cumplimiento_del_tallerista_o_instructor_con_los_horarios_establecidos = col_double(),
## la_resolucion_de_preguntas_dudas_y_el_enriquecimiento_de_comentarios = col_double(),
## trato_recibido_por_el_personal_que_labora_en_el_centro_comunitario = col_double(),
## calidad_de_la_informacion_brindada_por_el_personal_del_centro_comunitario = col_double(),
## salones_o_aulas = col_double(),
## salas_de_computo = col_double(),
## banos = col_double(),
## gimnasio_canchas = col_double(),
## polivalente = col_double()
## # ... with 27 more columns
## )
## ℹ Use `spec()` for the full column specifications.
# REVISIÓN DE ESTADÍSTICOS GENERALES
# Conteo de registros total y por periodo
n_total <- nrow(df_all) # Cuenta todas las filas para saber las cantidades de datos
registros_por_periodo <- df_all |> # Cuenta los registros por periodo (es decir, por base de datos)
count(anio_trimestre, name = "n_registros") |>
arrange(anio_trimestre)
# Medias y desviaciones estándar de las variables numéricas
# Detecta las columnas numéricas
num_cols <- df_all |>
select(where(is.numeric)) |>
colnames()
# Calcula la mediva y la desviación estándar para todas las variables
estad_global_num <- df_all |>
summarise(across(all_of(num_cols), #Da un resumen en un dataframe
list(media = ~mean(.x, na.rm = TRUE),
sd = ~sd(.x, na.rm = TRUE)),
.names = "{.col}__{.fn}"))
# En formato largo para facilitar lectura
estad_global_num_long <- estad_global_num |>
pivot_longer(everything(), #Para que sea en formato ancho
names_to = c("variable","estadistico"), #Separa la columna en el nombre de la variable original y si fue mean o sd lo que se usó
names_sep = "__",
values_to = "valor") |>
arrange(variable, estadistico) # Ordena los resultados
# Por periodo
estad_por_periodo <- df_all |>
group_by(anio_trimestre) |>
summarise(across(all_of(num_cols),
list(media = ~mean(.x, na.rm = TRUE), #Obtiene la media
sd = ~sd(.x, na.rm = TRUE)), #Obtiene la desviación
.names = "{.col}__{.fn}"),
.groups = "drop") |>
pivot_longer(-anio_trimestre,
names_to = c("variable","estadistico"),
names_sep = "__",
values_to = "valor") |>
arrange(anio_trimestre, variable, estadistico) #Organiza por año, variable, estadístico
# Distribución de frecuencias para las categóricas
cat_cols <- df_all |>
select(where(\(x) is.character(x) || is.factor(x))) |> #Obtiene todas las variables character o factor
select(-anio_trimestre, -source_file, -matches("sheet$")) |> #Excluye las variables no necesarias que creamos
colnames() #Obtiene los nombres de las columnas
# Frecuencias globales (top 10 por columna)
frecuencias_globales <- map(cat_cols, function(col) {
df_all |> #Con iteraciones se ven las frecuencias para cada variable factor
filter(!is.na(.data[[col]])) |>
tabyl(.data[[col]]) |> #Crea una tabla
arrange(desc(n)) |>
slice_head(n = 10) |> #Para que te de los top 10 frecuencias por columnas
mutate(variable = col, .before = 1)
}) |>
list_rbind() #Te da los resultados con el nombre de la variable
## Warning: Use of .data in tidyselect expressions was deprecated in tidyselect 1.2.0.
## ℹ Please use `all_of(var)` (or `any_of(var)`) instead of `.data[[var]]`
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
# Frecuencias por periodo (top 5 por variable y periodo)
frecuencias_por_periodo <- map(cat_cols, function(col) {
df_all |> #Con iteraciones se ven las frecuencias para cada variable factor por periodo
count(anio_trimestre, .data[[col]], name = "n") |> #Hace el conteo por periodo
group_by(anio_trimestre) |>
arrange(anio_trimestre, desc(n)) |> #Ordena por año y trimestre
slice_head(n = 5) |> # Te da el top 5
ungroup() |>
mutate(variable = col, .before = 1)
}) |>
list_rbind() #Te da los resultados con la variable
# EXTRACCIÓN DE RESPUESTAS TEXTUALES
# Identifica las columnas de texto
text_cols_candidates <- df_all |>
select(where(is.character)) |>
colnames()
# Filtra por patrones comunes de preguntas abiertas
patron_texto <- "(coment|observ|abiert|texto|otro|sugerenc|opinion)"
cols_abiertas <- text_cols_candidates[str_detect(text_cols_candidates, regex(patron_texto, ignore_case = TRUE))]
# Si no detecta por nombre, toma todas las character como abiertas:
if (length(cols_abiertas) == 0) cols_abiertas <- text_cols_candidates
# Crea una lista de dataframes, uno por columna (pregunta abierta)
abiertas_list <- map(cols_abiertas, function(col) {
df_all |>
select(anio_trimestre, source_file, !!sym(col)) |>
rename(respuesta_texto = !!sym(col)) |>
filter(!is.na(respuesta_texto), str_trim(respuesta_texto) != "")
})
names(abiertas_list) <- cols_abiertas #Crea una lista con las columnas de respuestas abiertas
# Guarda cada dataframe de respuestas abiertas a CSV
out_dir2 <- file.path(path_dir, "abiertas") #Crea una dirección dentro de la carpeta de trabajo para guardar los dataframes
if (!dir.exists(out_dir2)) dir.create(out_dir2, recursive = TRUE)
walk2(abiertas_list, names(abiertas_list), function(df_i, nombre_col) {
fn <- file.path(out_dir2, paste0("abierta_", nombre_col, ".csv")) #Guarda los dataframes con los nombres de las columnas y los guarda en csv
readr::write_csv(df_i, fn, na = "")
})
# GUARDANDO LOS ESTADÍSTICOS IMPORANTES EN ARCHIVOS CSV
out_dir_proc <- file.path(path_dir, "procesados")
if (!dir.exists(out_dir_proc)) dir.create(out_dir_proc, recursive = TRUE)
write_csv(df_all, file.path(out_dir_proc, "datos_unificados.csv"), na = "") #Esta es la base de datos final que vamos usar en csv
write_rds(df_all, file.path(out_dir_proc, "datos_unificados.rds")) #Esta es la base en rds
write_csv(registros_por_periodo, file.path(out_dir_proc, "registros_por_periodo.csv")) #Esta es de los registros por periodo
write_csv(estad_global_num_long, file.path( out_dir_proc, "estad_global_num.csv")) # Esta es para las estadísticas de mean y sd en general
write_csv(estad_por_periodo, file.path(out_dir_proc, "estad_por_periodo.csv")) # Esta es para las estadísticas por periodo
write_csv(frecuencias_globales, file.path(out_dir_proc, "frecuencias_globales_top10.csv")) #Esta es de las frecuencias generales
write_csv(frecuencias_por_periodo, file.path(out_dir_proc, "frecuencias_por_periodo_top5.csv")) #Esta es de las frecuencias por periodo
El análisis comenzó con la carga de librerías necesarias para el procesamiento y visualización de texto, entre ellas rvest, tm, wordcloud2, dplyr y ggplot2. Se trabajó con bases de datos en formato .csv que contienen respuestas abiertas, almacenadas en una carpeta llamada “abiertas”. Solo se seleccionaron aquellas que correspondían a preguntas relevantes para la investigación.
Antes del análisis, se revisó que los archivos no tuvieran valores vacíos ni caracteres extraños. Se observó que las tildes y las letras ñ se distorsionaban, por lo que se diseñó una función limpiar_texto que elimina acentos, protege las ñ y suprime emojis y otros símbolos no deseados. Las nuevas versiones de los archivos se guardaron en una carpeta llamada “limpios”.
Posteriormente, se cargaron los archivos limpios y se aplicó un proceso de limpieza adicional mediante la librería tm. Se unió el texto en un solo documento por archivo, se convirtieron las letras a minúsculas y se eliminaron puntuaciones, números, palabras vacías en español y términos poco informativos como “gracias” o “curso”. Cada texto limpio se transformó en un corpus y se almacenó en una lista para su análisis.
Finalmente, se generaron matrices de términos y documentos para identificar la frecuencia de palabras. Con base en ello, se elaboraron nubes de palabras y gráficos de barras con las 15 palabras más frecuentes por archivo. Las nubes se guardaron en formato HTML y los gráficos en formato PNG, cada uno en sus respectivas carpetas (“nubes_palabras” y “graficos_barras”).
# LIBRERÍAS
library(rvest)
##
## Attaching package: 'rvest'
## The following object is masked from 'package:readr':
##
## guess_encoding
library(xml2)
library(tm)
## Loading required package: NLP
##
## Attaching package: 'NLP'
## The following object is masked from 'package:ggplot2':
##
## annotate
library(wordcloud2)
library(readxl)
library(readr)
library(stringr)
library(stringi)
library(ggplot2)
library(dplyr)
library(htmlwidgets)
library(tidytext)
library(topicmodels)
# DATAFRAMES CON PREGUNTAS ABIERTAS
# Las bases de datos (una por cada pregunta abierta) fueron generadas desde la actividad número 1 y guardadas en una carpeta que se llama abiertas
# Nombres específicos de las preguntas que son de interés para la pregunta de investigación
nombres_especificos <- c("abierta_x10_si_tiene_algun_otro_curso_o_taller_que_le_interesaria_tomar_que_no_se_ofrece_en_el_centro_comunitario_favor_de_mencionarlo",
"abierta_comentarios_sobre_el_curso_o_taller_que_recibio",
"abierta_si_tiene_algun_otro_curso_o_taller_que_le_interesaria_tomar_que_no_se_ofrece_en_el_centro_comunitario_favor_de_mencionarlo",
"abierta_en_caso_de_elegir_otro_menciona_el_taller_al_que_asistes")
# Filtrar los archivos en la carpeta 'abiertas' que coincidan con los nombres específicos
ruta <- "C:/Users/tds1301/Desktop/Ciencia2/abiertas"
archivos_1 <- list.files(ruta, pattern = "\\.csv$", full.names = TRUE) # Obtener todos los archivos .csv
archivos <- archivos_1[basename(archivos_1) %in% paste0(nombres_especificos, ".csv")] # Filtrar solo los archivos específicos
# VERIFICACIÓN QUE NO CONTENGAN VALORES VACÍOS O CARACTERES EXTRAÑOS
# Nos dimos cuenta que los archivos si bien no contaban con vacíos, sí con caracteres extraños por cómo se estaban leyendo los acentos y las ñ, pero si intentabamos quitar todos los signos extraños, borraba las ñ, entonces hicimos la siguiente función:
limpiar_texto <- function(texto) {
# para proteger la ñ y Ñ
texto <- str_replace_all(texto, "ñ", "__ENYE__")
texto <- str_replace_all(texto, "Ñ", "__ENYEMAY__")
# para eliminar acentos (no elimina la letra, sólo los acentos)
texto <- stri_trans_general(texto, "Latin-ASCII")
# para volver a colocar las ñ, por que sino se hubieran borrado
texto <- str_replace_all(texto, "__ENYE__", "ñ")
texto <- str_replace_all(texto, "__ENYEMAY__", "Ñ")
# también nos dimos cuenta que había muchas respuestas con emojis, entonces con este código los eliminamos
texto <- str_replace_all(texto, "[^a-zA-Z0-9ñÑ .,;:!?()\"'\\-\\s]", "")
return(texto)
}
# En esta sección, usamos la función de limpiar_texto que habíamos creado
# primero, le pedimos que cree la carpeta "limpios" si no existe
carpeta_salida <- file.path(ruta, "limpios")
if (!dir.exists(carpeta_salida)) {
dir.create(carpeta_salida)
}
# Este código extrea el nombre de los archivos y lo guarda como nombre para cada uno
for (archivo in archivos) {
nombre <- tools::file_path_sans_ext(basename(archivo))
# esta parte es para leer .csv con UTF-8 para evitar errores con tildes y ñ
df <- read_csv(archivo, show_col_types = FALSE, locale = locale(encoding = "UTF-8"))
# nuestros dataframes tienen 3 columnas, una que es anio_trimestre, otra que es la base de donde salió el dato y luego la tercera columna que es respuesta_texto que es la que analizamos para todos los dataframes
if (ncol(df) < 3) { #este código se encarga de que revise las bases de datos y cheque que todas tengan tres columnas y si esto no es así, imprime el nombre del archivo que no tiene las tres columnas
cat("\n--------------------------------------------\n")
cat("Archivo:", nombre, "\n")
cat("No tiene al menos 3 columnas.\n")
next
}
# Debido a que sólo usamos la tercer columna, en esta parte se obtiene, y se aplica la función de limpiar_texto que se había creado
texto_no_limpio <- df[[3]]
texto_limpio <- limpiar_texto(texto_no_limpio) # Se guarda como texto_limpio cuando se le aplica la función
df[[3]] <- texto_limpio # se asigna a la columna 3 nuevamente
# Nos dimos cuenta que habían líneas que consistían únicamente de emojis, entonces con seste código eliminamos los vacíos de la columna 3
df <- df[!(is.na(df[[3]]) | str_trim(df[[3]]) == ""), ]
#Aquí guardamos las nuevas bases como estaban nombradas más el nombre "limpio_" en una carpeta nueva que habíamos creado que se llama limpios
write_csv(df, file.path(carpeta_salida, paste0("limpio_", nombre, ".csv")))
}
# LIMPIEZA Y PREPARACIÓN DE TEXTO
# ahora cargamos todos los csv que se encuentran en la carpeta limpios
ruta <- "C:/Users/tds1301/Desktop/Ciencia2/abiertas/limpios"
limpios <- list.files(ruta, pattern = "\\.csv$", full.names = TRUE) #se guardan en una lista llamada "limpios"
# aquí creamos una lista para guardar los corpus por archivo para poder hacer los gráficos despúes
corpus_lista <- list()
# se crea la función limpiar_con_tm que es para unir todo el texto de los archivos en uno solo
limpiar_con_tm <- function(texto_uno) {
# Unir todo el texto del archivo en uno solo
texto_unido <- paste(texto_uno, collapse = " ")
# creamos corpus con un solo documento con todos los vectores unidos
corpus <- Corpus(VectorSource(texto_unido))
# aplicamos la limpieza con corpus
corpus <- tm_map(corpus, content_transformer(tolower)) # para que todo esté en minúsculas
corpus <- tm_map(corpus, removePunctuation) # para quitar los signos de puntuación
corpus <- tm_map(corpus, removeNumbers) # para quitar los números
corpus <- tm_map(corpus, removeWords, stopwords("es")) # para quitar las palabras comunes en español
corpus <- tm_map(corpus, stripWhitespace) # para quitar los espacios en blacno
# palabras específicas a eliminar: estas se fueron ajustando según vimos los resultados de las gráficas
palabras_eliminar <- c("mas", "gracias", "si", "no", "curso", "clase", "personas", "siempre", "persona", "gusta", "clases", "solo", "areas", "hace", "estan", "club", "fina", "poner", "tener", "linea", "comunitario", "gustaria", "muchas", "asi", "momento", "pues", "muchas", "mucha", "mejor")
corpus <- tm_map(corpus, removeWords, palabras_eliminar)
return(corpus) # regresa el corpus limpio
}
# Esta parte es un loop porque lo hace para todos los archivos
for (archivo in limpios) {
nombre <- tools::file_path_sans_ext(basename(archivo)) # primero extra el nombre sin extensión
df <- read_csv(archivo, show_col_types = FALSE) # lee los archivos
if (ncol(df) < 3) {
cat("El archivo", nombre, "no tiene al menos 3 columnas. Saltando...\n")
next
} # nuevamente, revisa que los archivos tengan las 3 columnas que deberían tener
# extrae a la columna 3, que es la que usamos
textos <- df[[3]]
# guarda como corpus_limpio a los textos limpiados con la función de corpus
corpus_limpio <- limpiar_con_tm(textos)
# guarda todo en corpus_lista con el nombre original de los archivos
corpus_lista[[nombre]] <- corpus_limpio
}
#Nota: le pusimos warning=FALSE porque mandaba warning de que se estaban eliminando líneas de texto por la limpieza, pero esto es esperado dado que hay datos que no tenían contenido suficiente
limpiar_con_tm <- function(texto_uno) {
# Unir todo el texto del archivo en uno solo
texto_unido <- paste(texto_uno, collapse = " ")
# Verificar el contenido del texto unido
cat("Contenido de texto_unido:\n", substr(texto_unido, 1, 200), "\n")
# Crear corpus con un solo documento
corpus <- Corpus(VectorSource(texto_unido))
# Aplicar limpieza básica
corpus <- tm_map(corpus, content_transformer(tolower)) # Todo en minúsculas
corpus <- tm_map(corpus, removePunctuation) # Eliminar puntuación
corpus <- tm_map(corpus, removeNumbers) # Eliminar números
corpus <- tm_map(corpus, stripWhitespace) # Eliminar espacios extra
return(corpus) # Regresa el corpus limpio
}
# ANÁLISIS DE FRECUENCIA Y VISUALIZACIÓN
# Decidimos hacer un loop porque son muchas bases de datos
# También, nos dimos cuenta que workcloud2 no puede imprimir todas las nubes a la vez, entonces, en su lugar decidimos que todas las gráficas se guardaran en una carpeta a parte en html y las gráficas en otra carpeta como png
# para crear carpetas para guardar resultados
if (!dir.exists("nubes_palabras")) dir.create("nubes_palabras") #aquí se guardan las nubes
if (!dir.exists("graficos_barras")) dir.create("graficos_barras") #aquí se guardan las gráficas de barras
for (nombre in names(corpus_lista)) { # aquí comienza el loop para cada uno de los archivos en la lista limpia
corpus <- corpus_lista[[nombre]]
# Crear una matriz término-documento
dtm <- DocumentTermMatrix(corpus)
# Sumar las columnas para obtener el conteo total de cada término
matriz <- as.matrix(dtm)
conteo <- colSums(matriz)
# para ordenar de mayor a menor frecuencia
conteo_ordenado <- sort(conteo, decreasing = TRUE)
# Se crea el data frame para graficar las nubes y barras, según la frecuencia de las palabras
df_palabras <- data.frame(
palabra = names(conteo_ordenado),
frecuencia = as.numeric(conteo_ordenado),
stringsAsFactors = FALSE
)
# Para crear la nube de palabras
nube <- wordcloud2(df_palabras, size = 0.5, color = "random-light", backgroundColor = "black")
# para guardar la nube como archivo html en la carpeta que habíamos creado
saveWidget(nube, file = paste0("nubes_palabras/nube_", nombre, ".html"), selfcontained = TRUE)
# Ahora, para los gráficos de barras, esta parte saca el top15 de mayores frecuencias
top15 <- head(df_palabras, 15)
# para ordenar para que la barra con mayor frecuencia quede arriba
top15$palabra <- factor(top15$palabra, levels = rev(top15$palabra))
# para crear el gráfico
grafico_barras <- ggplot(top15, aes(x = palabra, y = frecuencia)) + # determina los ejes
geom_col(fill = "steelblue") + # determina el color de la gráfica
coord_flip() +
labs(title = paste("15 palabras más frecuentes:", nombre), # determina el título más el nombre de la base de datos
x = "Palabra",
y = "Frecuencia") +
theme_minimal() # dice el tema de diseño para las gráficas
# para guardar los gráficos de barras como png en la carpeta creada
ggsave(filename = paste0("graficos_barras/barras_", nombre, ".png"), plot = grafico_barras, width = 8, height = 6)
}
# ANÁLISIS DE TÓPICOS POR PREGUNTA ABIERTA
# para crear una lista para guardar las DTMs
dtm_lista <- list()
# para crear la DTM para cada archivo en corpus_lista
for (nombre in names(corpus_lista)) {
corpus <- corpus_lista[[nombre]]
dtm <- DocumentTermMatrix(corpus)
dtm_lista[[nombre]] <- dtm
}
# Definir el número de tópicos
num_topics <- 5
# Crear una lista para guardar los modelos LDA
lda_models <- list()
# Ajustar el modelo LDA para cada DTM
for (nombre in names(dtm_lista)) {
dtm <- dtm_lista[[nombre]]
lda_model <- LDA(dtm, k = num_topics, control = list(seed = 123))
lda_models[[nombre]] <- lda_model
}
# Extraer las palabras clave por tópico
terms_lda <- list()
for (nombre in names(lda_models)) {
lda_model <- lda_models[[nombre]]
terms_lda[[nombre]] <- terms(lda_model, 10)
}
# ANÁLISIS DE TÓPICOS PARA EL TEXTO COMPLETO
# Para el texto de todos los archivos en un único corpus
corpus_combinado <- Corpus(VectorSource(NULL)) # crear un corpus vacío
# Para definir las stopwords en español
stopwords_es <- stopwords("es")
palabras_eliminar <- c("mas", "gracias", "si", "no", "curso", "clase", "personas", "siempre", "persona", "gusta", "clases", "solo", "areas", "hace", "estan", "club", "fina", "poner", "tener", "linea", "comunitario", "gustaria", "muchas", "asi", "momento", "pues", "muchas", "mucha", "mejor")
# Para cargar y combinar los textos de cada archivo limpio en un solo corpus
for (archivo in limpios) {
df <- read_csv(archivo, show_col_types = FALSE)
textos <- df[[3]] # para la tercera columna que contiene los textos
# para limpiar el texto de cada archivo con la función anterior
textos_limpios <- limpiar_con_tm(textos)
# para eliminar las stopwords del texto limpio
textos_sin_extras <- tm_map(textos_limpios, removeWords, palabras_eliminar)
textos_sin_stopwords <- tm_map(textos_sin_extras, removeWords, stopwords_es)
# para unir el texto sin stopwords al corpus combinado
corpus_combinado <- append(corpus_combinado, textos_sin_stopwords)
}
## Contenido de texto_unido:
## Son muy buenos los cursos ya que nos ayudan aprender cosas nuevas y desde casa es lo mejor. Excelente taller Buenos comentarios Bien Excelente instructor, Prof. ERIK leal, es muy paciente Excelente Ex
## Contenido de texto_unido:
## idiomas extranjeros Aerobics kick boxing karate karate karate karate karate karate karate karate karate karate karate karate karate karate karate karate karate karate karate karate karate . . . . . NI
## Contenido de texto_unido:
## Gimnasio 0 Ninguno Belleza 0 0 Ninguno Joyeria Futbol para adolescentes 0 Panaderia 0 0 Belleza 0 0 Reposteria Taller para poner uñas Barber Inteligencia artificial 0 Corte y confeccion Cocina.para n
## Contenido de texto_unido:
## No Artes marciales mixtas Ninguno Pintura Confeccion de mochilas y bolsas, reciclaje de ropa Hasta ahora todo bien Serigrafia Bordado No Dibujo Scrapbook , Bullet Journal Pasta flexible Reposteria Gui
# matriz
dtm_combinado <- DocumentTermMatrix(corpus_combinado)
# LDA
num_topics <- 5 # Número de tópicos
lda_model_ALL <- LDA(dtm_combinado, k = num_topics, control = list(seed = 123))
# palabras más representativas por tópico
terms_lda_ALL <- terms(lda_model_ALL, 10)
cat("Registros totales:", n_total, "\n") # Escribe el conteo
## Registros totales: 31524
print(registros_por_periodo) # Da una tabla con los conteos por periodo
## # A tibble: 11 × 2
## anio_trimestre n_registros
## <chr> <int>
## 1 2017_4 410
## 2 2018_4 376
## 3 2019_4 498
## 4 2020_4 848
## 5 2021_4 3702
## 6 2022_1 2003
## 7 2024_2 4607
## 8 2024_3 4592
## 9 2024_4 4191
## 10 2025_1 5262
## 11 2025_2 5035
El dataset contiene un total de 11 periodos (anio_trimestre) con 11 observaciones agregadas, que representan la cantidad de registros de encuestas por trimestre entre 2017 y 2025.En total se dispone de más de 5,000 observaciones individuales en los años recientes,lo que permite analizar tendencias temporales y de participación.
Para el análisis cuantitativo: - Calidad de la información brindada por el personal del centro - Conocimiento del tallerista o instructor - Contenido y materiales del curso/taller - Trato recibido por el personal del centro
Para el análisis cualitativo: - Curso o taller que le interesaría tomar (si no se ofrece en el centro) - Comentarios sobre el curso recibido - Elección de otro taller al que asiste - Género, estado civil, ocupación, escolaridad - Curso o taller que cursa o terminó
Estas variables son las base para examinar la participación, satisfacción y preferencias de los usuarios de los centros comunitarios, además de explorar patrones de género y posibles relaciones entre perfil sociodemográfico y tipo de taller.
# Define las variables de interés para la pregunta de investigación
numericas_pregunta <- c(
"x2_cuantos_anos_cumplidos_tiene", "el_contenido_o_temas_del_curso_taller", "la_calidad_y_cantidad_de_materiales_y_equipo_utilizados_en_el_curso_taller", "el_conocimiento_del_tallerista_o_instructor_sobre_el_tema_del_curso_taller", "trato_recibido_por_el_personal_que_labora_en_el_centro_comunitario", "calidad_de_la_informacion_brindada_por_el_personal_del_centro_comunitario"
)
# Imprime una tabla
estad_global_num_long %>%
filter(variable %in% numericas_pregunta) %>%
kable()
| variable | estadistico | valor |
|---|---|---|
| calidad_de_la_informacion_brindada_por_el_personal_del_centro_comunitario | media | 9.7084373 |
| calidad_de_la_informacion_brindada_por_el_personal_del_centro_comunitario | sd | 0.8729843 |
| el_conocimiento_del_tallerista_o_instructor_sobre_el_tema_del_curso_taller | media | 9.7358505 |
| el_conocimiento_del_tallerista_o_instructor_sobre_el_tema_del_curso_taller | sd | 0.8246910 |
| el_contenido_o_temas_del_curso_taller | media | 9.6712339 |
| el_contenido_o_temas_del_curso_taller | sd | 0.9773256 |
| la_calidad_y_cantidad_de_materiales_y_equipo_utilizados_en_el_curso_taller | media | 9.4403025 |
| la_calidad_y_cantidad_de_materiales_y_equipo_utilizados_en_el_curso_taller | sd | 1.3809906 |
| trato_recibido_por_el_personal_que_labora_en_el_centro_comunitario | media | 9.6219541 |
| trato_recibido_por_el_personal_que_labora_en_el_centro_comunitario | sd | 0.9524982 |
| x2_cuantos_anos_cumplidos_tiene | media | 37.6505242 |
| x2_cuantos_anos_cumplidos_tiene | sd | 15.6558161 |
# Define las variables de interés para la pregunta de investigación
numericas_pregunta <- c(
"x2_cuantos_anos_cumplidos_tiene", "el_contenido_o_temas_del_curso_taller", "la_calidad_y_cantidad_de_materiales_y_equipo_utilizados_en_el_curso_taller", "el_conocimiento_del_tallerista_o_instructor_sobre_el_tema_del_curso_taller", "trato_recibido_por_el_personal_que_labora_en_el_centro_comunitario", "calidad_de_la_informacion_brindada_por_el_personal_del_centro_comunitario"
)
# Imprime una tabla
estad_global_num_long %>%
filter(variable %in% numericas_pregunta) %>%
kable()
| variable | estadistico | valor |
|---|---|---|
| calidad_de_la_informacion_brindada_por_el_personal_del_centro_comunitario | media | 9.7084373 |
| calidad_de_la_informacion_brindada_por_el_personal_del_centro_comunitario | sd | 0.8729843 |
| el_conocimiento_del_tallerista_o_instructor_sobre_el_tema_del_curso_taller | media | 9.7358505 |
| el_conocimiento_del_tallerista_o_instructor_sobre_el_tema_del_curso_taller | sd | 0.8246910 |
| el_contenido_o_temas_del_curso_taller | media | 9.6712339 |
| el_contenido_o_temas_del_curso_taller | sd | 0.9773256 |
| la_calidad_y_cantidad_de_materiales_y_equipo_utilizados_en_el_curso_taller | media | 9.4403025 |
| la_calidad_y_cantidad_de_materiales_y_equipo_utilizados_en_el_curso_taller | sd | 1.3809906 |
| trato_recibido_por_el_personal_que_labora_en_el_centro_comunitario | media | 9.6219541 |
| trato_recibido_por_el_personal_que_labora_en_el_centro_comunitario | sd | 0.9524982 |
| x2_cuantos_anos_cumplidos_tiene | media | 37.6505242 |
| x2_cuantos_anos_cumplidos_tiene | sd | 15.6558161 |
estad_resumen <- tribble(
~variable, ~estadistico, ~valor,
"calidad_de_la_informacion_brindada_por_el_personal_del_centro_comunitario", "media", 9.7084373,
"calidad_de_la_informacion_brindada_por_el_personal_del_centro_comunitario", "sd", 0.8729843,
"el_conocimiento_del_tallerista_o_instructor_sobre_el_tema_del_curso_taller", "media", 9.7358505,
"el_conocimiento_del_tallerista_o_instructor_sobre_el_tema_del_curso_taller", "sd", 0.8246910,
"el_contenido_o_temas_del_curso_taller", "media", 9.6712339,
"el_contenido_o_temas_del_curso_taller", "sd", 0.9773256,
"la_calidad_y_cantidad_de_materiales_y_equipo_utilizados_en_el_curso_taller", "media", 9.4403025,
"la_calidad_y_cantidad_de_materiales_y_equipo_utilizados_en_el_curso_taller", "sd", 1.3809906,
"trato_recibido_por_el_personal_que_labora_en_el_centro_comunitario", "media", 9.6219541,
"trato_recibido_por_el_personal_que_labora_en_el_centro_comunitario", "sd", 0.9524982,
"x2_cuantos_anos_cumplidos_tiene", "media", 37.6505242,
"x2_cuantos_anos_cumplidos_tiene", "sd", 15.6558161
)
# Gráfico de barras para las medias de satisfacción
estad_resumen %>%
filter(estadistico == "media", !grepl("x2_", variable)) %>%
mutate(variable = recode(variable,
"calidad_de_la_informacion_brindada_por_el_personal_del_centro_comunitario" = "Calidad de la información",
"el_conocimiento_del_tallerista_o_instructor_sobre_el_tema_del_curso_taller" = "Conocimiento del tallerista",
"el_contenido_o_temas_del_curso_taller" = "Contenido del curso",
"la_calidad_y_cantidad_de_materiales_y_equipo_utilizados_en_el_curso_taller" = "Calidad de materiales",
"trato_recibido_por_el_personal_que_labora_en_el_centro_comunitario" = "Trato del personal"
)) %>%
ggplot(aes(x = valor, y = reorder(variable, valor))) +
geom_vline(xintercept = mean(c(9.44, 9.74, 9.71, 9.67, 9.62)),
linetype = "dashed", color = "gray60") +
geom_point(color = "#4B9CD3", size = 5) +
geom_text(aes(label = round(valor, 2)), hjust = -0.3, size = 4) +
scale_x_continuous(limits = c(8.5, 10)) +
labs(
title = "Promedio de satisfacción por dimensión evaluada",
x = "Media de satisfacción",
y = NULL,
caption = "Línea discontinua = promedio general de satisfacción"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.caption = element_text(size = 9, hjust = 0.5, color = "gray40"),
axis.text.y = element_text(size = 11)
)
estad_media_sd <- estad_resumen %>%
pivot_wider(names_from = estadistico, values_from = valor) %>%
filter(!grepl("x2_", variable)) %>%
mutate(variable = recode(variable,
"calidad_de_la_informacion_brindada_por_el_personal_del_centro_comunitario" = "Calidad de la información",
"el_conocimiento_del_tallerista_o_instructor_sobre_el_tema_del_curso_taller" = "Conocimiento del tallerista",
"el_contenido_o_temas_del_curso_taller" = "Contenido del curso",
"la_calidad_y_cantidad_de_materiales_y_equipo_utilizados_en_el_curso_taller" = "Calidad de materiales",
"trato_recibido_por_el_personal_que_labora_en_el_centro_comunitario" = "Trato del personal"
))
# Graficar
estad_media_sd <- estad_resumen %>%
pivot_wider(names_from = estadistico, values_from = valor) %>%
filter(!grepl("x2_", variable)) %>%
mutate(variable = recode(variable,
"calidad_de_la_informacion_brindada_por_el_personal_del_centro_comunitario" = "Calidad de la información",
"el_conocimiento_del_tallerista_o_instructor_sobre_el_tema_del_curso_taller" = "Conocimiento del tallerista",
"el_contenido_o_temas_del_curso_taller" = "Contenido del curso",
"la_calidad_y_cantidad_de_materiales_y_equipo_utilizados_en_el_curso_taller" = "Calidad de materiales",
"trato_recibido_por_el_personal_que_labora_en_el_centro_comunitario" = "Trato del personal"
))
# Calcular promedios globales
media_prom <- mean(estad_media_sd$media)
sd_prom <- mean(estad_media_sd$sd)
# Graficar con estilo mejorado
ggplot(estad_media_sd, aes(x = sd, y = media, label = variable)) +
# Líneas de referencia (cuadrantes)
geom_hline(yintercept = media_prom, linetype = "dashed", color = "gray60") +
geom_vline(xintercept = sd_prom, linetype = "dashed", color = "gray60") +
# Puntos coloreados por variable
geom_point(aes(color = variable), size = 5, alpha = 0.9, show.legend = FALSE) +
geom_text(nudge_y = 0.045, size = 4) +
# Escalas ajustadas para centrar los datos
scale_y_continuous(limits = c(9.4, 9.8)) +
scale_x_continuous(limits = c(0.75, 1.45)) +
# Colores suaves y profesionales
scale_color_manual(values = c(
"Conocimiento del tallerista" = "#1f78b4",
"Calidad de la información" = "#33a02c",
"Contenido del curso" = "#ff7f00",
"Trato del personal" = "#6a3d9a",
"Calidad de materiales" = "#e31a1c"
)) +
# Etiquetas y diseño general
labs(
title = "Nivel y consistencia de satisfacción por dimensión",
subtitle = "Línea horizontal: media general | Línea vertical: desviación estándar promedio",
x = "Desviación estándar (variabilidad de respuestas)",
y = "Media (nivel de satisfacción)"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, size = 10, color = "gray40"),
axis.text = element_text(size = 11),
panel.grid.minor = element_blank()
)
Gráfica /Tabla #1 Reflejan un escenario positivo y satisfactorio entre los usuarios. Se percibe un trato profesional y amable por parte del personal del centro comunitario y los talleristas, así como una buena calidad tanto en el contenido de los talleres como en los materiales. Mejorar la cantidad y la calidad de los materiales usados en los talleres.
Grafíca #2 La gráfica muestra el promedio de satisfacción por dimensión, con niveles muy altos en todos los aspectos.Destacan el conocimiento del tallerista (9.74) y la calidad de la información (9.71), mientras que la calidad de materiales (9.44) es la menor, aunque sigue siendo elevada.Las diferencias son mínimas, lo que refleja un desempeño equilibrado y una satisfacción general sostenida entre los usuarios.
Gráfica #3 La gráfica muestra la relación entre el nivel de satisfacción y la consistencia de las respuestas.Destacan conocimiento del tallerista y calidad de la información por su alta satisfacción y baja variabilidad. En cambio, la calidad de materiales presenta una mayor dispersión y una media ligeramente menor, reflejando opiniones más diversas. En general, se mantiene una tendencia positiva y estable, con áreas de mejora en los recursos materiales
# Define las variables de interés para la pregunta de investigación
variables_pregunta <- c(
"x1_cual_es_su_genero",
"x3_actualmente_cual_es_su_estado_civil",
"x4_cual_es_su_maximo_nivel_de_escolaridad_alcanzado_al_dia_de_hoy",
"x5_a_que_se_dedica_actualmente_puede_seleccionar_una_o_mas_opciones",
"curso_o_taller_que_cursa_o_termino",
"centro_comunitario",
"x6_lo_que_usted_aprendio_en_el_curso_taller_en_que_ambito_de_su_vida_lo_aplicaria_puede_marcar_hasta_dos_opciones"
)
# Imprime una tabla
frecuencias_globales %>%
filter(variable %in% variables_pregunta) %>%
select(variable, n, percent, x1_cual_es_su_genero, x3_actualmente_cual_es_su_estado_civil, x4_cual_es_su_maximo_nivel_de_escolaridad_alcanzado_al_dia_de_hoy, x5_a_que_se_dedica_actualmente_puede_seleccionar_una_o_mas_opciones, curso_o_taller_que_cursa_o_termino, centro_comunitario, x6_lo_que_usted_aprendio_en_el_curso_taller_en_que_ambito_de_su_vida_lo_aplicaria_puede_marcar_hasta_dos_opciones
) %>%
kable()
| variable | n | percent | x1_cual_es_su_genero | x3_actualmente_cual_es_su_estado_civil | x4_cual_es_su_maximo_nivel_de_escolaridad_alcanzado_al_dia_de_hoy | x5_a_que_se_dedica_actualmente_puede_seleccionar_una_o_mas_opciones | curso_o_taller_que_cursa_o_termino | centro_comunitario | x6_lo_que_usted_aprendio_en_el_curso_taller_en_que_ambito_de_su_vida_lo_aplicaria_puede_marcar_hasta_dos_opciones |
|---|---|---|---|---|---|---|---|---|---|
| x1_cual_es_su_genero | 1765 | 0.8811782 | Femenino | NA | NA | NA | NA | NA | NA |
| x1_cual_es_su_genero | 233 | 0.1163255 | Masculino | NA | NA | NA | NA | NA | NA |
| x1_cual_es_su_genero | 5 | 0.0024963 | Prefiero no decirlo | NA | NA | NA | NA | NA | NA |
| x3_actualmente_cual_es_su_estado_civil | 1058 | 0.5282077 | NA | Casado(a) | NA | NA | NA | NA | NA |
| x3_actualmente_cual_es_su_estado_civil | 536 | 0.2675986 | NA | Soltero(a) | NA | NA | NA | NA | NA |
| x3_actualmente_cual_es_su_estado_civil | 220 | 0.1098352 | NA | Vive en unión libre | NA | NA | NA | NA | NA |
| x3_actualmente_cual_es_su_estado_civil | 71 | 0.0354468 | NA | Divorciado(a) | NA | NA | NA | NA | NA |
| x3_actualmente_cual_es_su_estado_civil | 59 | 0.0294558 | NA | Está separado(a) | NA | NA | NA | NA | NA |
| x3_actualmente_cual_es_su_estado_civil | 59 | 0.0294558 | NA | Viudo(a) | NA | NA | NA | NA | NA |
| x4_cual_es_su_maximo_nivel_de_escolaridad_alcanzado_al_dia_de_hoy | 466 | 0.2326510 | NA | NA | Secundaria completa | NA | NA | NA | NA |
| x4_cual_es_su_maximo_nivel_de_escolaridad_alcanzado_al_dia_de_hoy | 311 | 0.1552671 | NA | NA | Preparatoria o bachillerato completo | NA | NA | NA | NA |
| x4_cual_es_su_maximo_nivel_de_escolaridad_alcanzado_al_dia_de_hoy | 255 | 0.1273090 | NA | NA | Carrera técnica o comercial completa | NA | NA | NA | NA |
| x4_cual_es_su_maximo_nivel_de_escolaridad_alcanzado_al_dia_de_hoy | 235 | 0.1173240 | NA | NA | Universidad completa | NA | NA | NA | NA |
| x4_cual_es_su_maximo_nivel_de_escolaridad_alcanzado_al_dia_de_hoy | 205 | 0.1023465 | NA | NA | Preparatoria o bachillerato incompleto | NA | NA | NA | NA |
| x4_cual_es_su_maximo_nivel_de_escolaridad_alcanzado_al_dia_de_hoy | 86 | 0.0429356 | NA | NA | Secundaria incompleta | NA | NA | NA | NA |
| x4_cual_es_su_maximo_nivel_de_escolaridad_alcanzado_al_dia_de_hoy | 85 | 0.0424363 | NA | NA | Primaria incompleta | NA | NA | NA | NA |
| x4_cual_es_su_maximo_nivel_de_escolaridad_alcanzado_al_dia_de_hoy | 74 | 0.0369446 | NA | NA | Universidad incompleta | NA | NA | NA | NA |
| x4_cual_es_su_maximo_nivel_de_escolaridad_alcanzado_al_dia_de_hoy | 68 | 0.0339491 | NA | NA | Primaria completa | NA | NA | NA | NA |
| x4_cual_es_su_maximo_nivel_de_escolaridad_alcanzado_al_dia_de_hoy | 67 | 0.0334498 | NA | NA | Carrera técnica o comercial incompleta | NA | NA | NA | NA |
| x5_a_que_se_dedica_actualmente_puede_seleccionar_una_o_mas_opciones | 884 | 0.4413380 | NA | NA | NA | Se dedica a los quehaceres del hogar | NA | NA | NA |
| x5_a_que_se_dedica_actualmente_puede_seleccionar_una_o_mas_opciones | 331 | 0.1652521 | NA | NA | NA | Está trabajando | NA | NA | NA |
| x5_a_que_se_dedica_actualmente_puede_seleccionar_una_o_mas_opciones | 278 | 0.1387918 | NA | NA | NA | Es estudiante | NA | NA | NA |
| x5_a_que_se_dedica_actualmente_puede_seleccionar_una_o_mas_opciones | 101 | 0.0504244 | NA | NA | NA | Es pensionado o jubilado | NA | NA | NA |
| x5_a_que_se_dedica_actualmente_puede_seleccionar_una_o_mas_opciones | 83 | 0.0414378 | NA | NA | NA | Está buscando trabajo | NA | NA | NA |
| x5_a_que_se_dedica_actualmente_puede_seleccionar_una_o_mas_opciones | 49 | 0.0244633 | NA | NA | NA | Está buscando trabajo, Se dedica a los quehaceres del hogar | NA | NA | NA |
| x5_a_que_se_dedica_actualmente_puede_seleccionar_una_o_mas_opciones | 33 | 0.0164753 | NA | NA | NA | Se dedica a los quehaceres del hogar, Es estudiante | NA | NA | NA |
| x5_a_que_se_dedica_actualmente_puede_seleccionar_una_o_mas_opciones | 31 | 0.0154768 | NA | NA | NA | Está trabajando, Se dedica a los quehaceres del hogar | NA | NA | NA |
| x5_a_que_se_dedica_actualmente_puede_seleccionar_una_o_mas_opciones | 26 | 0.0129805 | NA | NA | NA | Está trabajando, Es estudiante | NA | NA | NA |
| x5_a_que_se_dedica_actualmente_puede_seleccionar_una_o_mas_opciones | 12 | 0.0059910 | NA | NA | NA | Está trabajando, Se dedica a los quehaceres del hogar, Es estudiante | NA | NA | NA |
| centro_comunitario | 5713 | 0.1812270 | NA | NA | NA | NA | NA | SAN BERNABE | NA |
| centro_comunitario | 2275 | 0.0721672 | NA | NA | NA | NA | NA | MONTE KRISTAL | NA |
| centro_comunitario | 2043 | 0.0648078 | NA | NA | NA | NA | NA | SANTA FE | NA |
| centro_comunitario | 1969 | 0.0624603 | NA | NA | NA | NA | NA | LA ALIANZA | NA |
| centro_comunitario | 1562 | 0.0495495 | NA | NA | NA | NA | NA | ALIANZA REAL | NA |
| centro_comunitario | 1483 | 0.0470435 | NA | NA | NA | NA | NA | LOS ENCINOS | NA |
| centro_comunitario | 1178 | 0.0373684 | NA | NA | NA | NA | NA | EULALIO VILLARREAL | NA |
| centro_comunitario | 1139 | 0.0361312 | NA | NA | NA | NA | NA | TIERRA PROPIA | NA |
| centro_comunitario | 1022 | 0.0324197 | NA | NA | NA | NA | NA | HECTOR CABALLERO | NA |
| centro_comunitario | 921 | 0.0292158 | NA | NA | NA | NA | NA | INDEPENDENCIA | NA |
| curso_o_taller_que_cursa_o_termino | 1197 | 0.0384714 | NA | NA | NA | NA | ZUMBA | NA | NA |
| curso_o_taller_que_cursa_o_termino | 651 | 0.0209231 | NA | NA | NA | NA | ATENCIÓN PSICOLÓGICA INDIVIDUAL | NA | NA |
| curso_o_taller_que_cursa_o_termino | 523 | 0.0168092 | NA | NA | NA | NA | BAILOTERAPIA | NA | NA |
| curso_o_taller_que_cursa_o_termino | 490 | 0.0157485 | NA | NA | NA | NA | BELLEZA I | NA | NA |
| curso_o_taller_que_cursa_o_termino | 459 | 0.0147522 | NA | NA | NA | NA | ACONDICIONAMIENTO FÍSICO | NA | NA |
| curso_o_taller_que_cursa_o_termino | 431 | 0.0138523 | NA | NA | NA | NA | PIÑATAS | NA | NA |
| curso_o_taller_que_cursa_o_termino | 415 | 0.0133380 | NA | NA | NA | NA | EDUCACIÓN INICIAL | NA | NA |
| curso_o_taller_que_cursa_o_termino | 375 | 0.0120525 | NA | NA | NA | NA | GIMNASIA | NA | NA |
| curso_o_taller_que_cursa_o_termino | 372 | 0.0119560 | NA | NA | NA | NA | CORTE Y CONFECCIÓN I | NA | NA |
| curso_o_taller_que_cursa_o_termino | 365 | 0.0117311 | NA | NA | NA | NA | TAE KWON DO PRINCIPIANTE | NA | NA |
| x6_lo_que_usted_aprendio_en_el_curso_taller_en_que_ambito_de_su_vida_lo_aplicaria_puede_marcar_hasta_dos_opciones | 327 | 0.1632551 | NA | NA | NA | NA | NA | NA | 1. Laboral / emprendimiento de un negocio |
| x6_lo_que_usted_aprendio_en_el_curso_taller_en_que_ambito_de_su_vida_lo_aplicaria_puede_marcar_hasta_dos_opciones | 281 | 0.1402896 | NA | NA | NA | NA | NA | NA | 1. Laboral / emprendimiento de un negocio, 3. Personal |
| x6_lo_que_usted_aprendio_en_el_curso_taller_en_que_ambito_de_su_vida_lo_aplicaria_puede_marcar_hasta_dos_opciones | 230 | 0.1148278 | NA | NA | NA | NA | NA | NA | 3. Personal |
| x6_lo_que_usted_aprendio_en_el_curso_taller_en_que_ambito_de_su_vida_lo_aplicaria_puede_marcar_hasta_dos_opciones | 214 | 0.1068397 | NA | NA | NA | NA | NA | NA | 1. Laboral / emprendimiento de un negocio, 4. Familiar |
| x6_lo_que_usted_aprendio_en_el_curso_taller_en_que_ambito_de_su_vida_lo_aplicaria_puede_marcar_hasta_dos_opciones | 192 | 0.0958562 | NA | NA | NA | NA | NA | NA | 3. Personal, 4. Familiar |
| x6_lo_que_usted_aprendio_en_el_curso_taller_en_que_ambito_de_su_vida_lo_aplicaria_puede_marcar_hasta_dos_opciones | 163 | 0.0813779 | NA | NA | NA | NA | NA | NA | 3. Personal, 5. Salud |
| x6_lo_que_usted_aprendio_en_el_curso_taller_en_que_ambito_de_su_vida_lo_aplicaria_puede_marcar_hasta_dos_opciones | 97 | 0.0484274 | NA | NA | NA | NA | NA | NA | 4. Familiar |
| x6_lo_que_usted_aprendio_en_el_curso_taller_en_que_ambito_de_su_vida_lo_aplicaria_puede_marcar_hasta_dos_opciones | 94 | 0.0469296 | NA | NA | NA | NA | NA | NA | 5. Salud |
| x6_lo_que_usted_aprendio_en_el_curso_taller_en_que_ambito_de_su_vida_lo_aplicaria_puede_marcar_hasta_dos_opciones | 66 | 0.0329506 | NA | NA | NA | NA | NA | NA | 2. Académico, 3. Personal |
| x6_lo_que_usted_aprendio_en_el_curso_taller_en_que_ambito_de_su_vida_lo_aplicaria_puede_marcar_hasta_dos_opciones | 50 | 0.0249626 | NA | NA | NA | NA | NA | NA | 2. Académico |
#(Variables: “abierta_x10_” y “abierta_si_tiene_”) #Las palabras más frecuentes: repostería, cocina, carpintería, confección, belleza, inglés, computación, reflejan un equilibrio entre oficios tradicionales, capacitación técnica y desarrollo personal. Los participantes muestran interés por talleres prácticos y útiles para el autoempleo o la vida cotidiana. Además, la demanda por cursos de idiomas y tecnología evidencia una búsqueda de modernización y competitividad laboral.
#Comentarios sobre los cursos recibidos #(Variable: “abierta_comentarios_sobre_el_curso_o_taller_que_recibio”) #Términos como excelente, bueno, gusto, satisfecho revelan una valoración positiva generalizada. Los participantes destacan la enseñanza, la atención y el ambiente, reforzando la confianza en los instructores y la percepción de utilidad de los talleres.
#Elección de otros talleres #(Variable: “abierta_en_caso_de_elegir_otro_menciona_el_taller_al_que_asistes”) #Las menciones más comunes: repostería, piñatas, inglés, belleza, pintura, gimnasia, karate, muestran preferencia por actividades creativas y de bienestar personal. Este patrón sugiere una visión integral del aprendizaje, que combina expresión artística, convivencia social y desarrollo técnico.
# Para visualizar las palabras clave por archivo de las 4 variables más imporantes para la pregunta de investigación
print(terms_lda[[1]])
## Topic 1 Topic 2 Topic 3 Topic 4 Topic 5
## [1,] "bueno" "bueno" "bien" "bien" "excelente"
## [2,] "bien" "excelente" "excelente" "buen" "bueno"
## [3,] "taller" "maestra" "bueno" "bueno" "ninguno"
## [4,] "maestro" "taller" "maestra" "excelente" "maestra"
## [5,] "buen" "buen" "buena" "buena" "taller"
## [6,] "exelente" "bien" "taller" "niños" "buen"
## [7,] "niños" "niños" "buen" "espacio" "exelente"
## [8,] "excelente" "maestro" "falta" "taller" "buena"
## [9,] "espacio" "buena" "exelente" "exelente" "buenos"
## [10,] "ninguno" "explicado" "material" "material" "bien"
print(terms_lda[[2]])
## Topic 1 Topic 2 Topic 3 Topic 4 Topic 5
## [1,] "reposteria" "reposteria" "taller" "reposteria" "reposteria"
## [2,] "piñatas" "taller" "ingles" "ingles" "piñatas"
## [3,] "uñas" "pasta" "pasta" "gimnasia" "flexible"
## [4,] "gimnasia" "piñatas" "fieltro" "taller" "panaderia"
## [5,] "ingles" "uñas" "piñatas" "niños" "pasta"
## [6,] "flexible" "gimnasia" "uñas" "karate" "pintura"
## [7,] "taller" "ingles" "panaderia" "panaderia" "uñas"
## [8,] "zumba" "belleza" "belleza" "excel" "belleza"
## [9,] "pasteleria" "niños" "acondicionamiento" "kekitos" "taller"
## [10,] "belleza" "dulces" "dulces" "piñatas" "dulces"
print(terms_lda[[3]])
## Topic 1 Topic 2 Topic 3 Topic 4 Topic 5
## [1,] "ninguno" "ninguno" "ninguno" "ingles" "ninguno"
## [2,] "ingles" "bien" "cocina" "computacion" "ingles"
## [3,] "reposteria" "reposteria" "reposteria" "bordado" "belleza"
## [4,] "natacion" "musica" "ingles" "ninguno" "reposteria"
## [5,] "cocina" "carpinteria" "corte" "box" "repujado"
## [6,] "yoga" "niños" "uñas" "carpinteria" "niños"
## [7,] "costura" "corte" "box" "satisfecho" "yoga"
## [8,] "bien" "globoflexia" "carpinteria" "uñas" "velas"
## [9,] "barber" "pintura" "belleza" "pintura" "pintura"
## [10,] "box" "confeccion" "satisfecho" "costura" "globoflexia"
print(terms_lda[[4]])
## Topic 1 Topic 2 Topic 3 Topic 4 Topic 5
## [1,] "cocina" "ninguno" "ninguno" "ninguno" "ninguno"
## [2,] "reposteria" "cocina" "corte" "bien" "bien"
## [3,] "tejido" "bien" "reposteria" "belleza" "reposteria"
## [4,] "ninguno" "reposteria" "cursos" "confeccion" "carpinteria"
## [5,] "auxilios" "taller" "computacion" "dulces" "cursos"
## [6,] "confeccion" "pestañas" "taller" "ingles" "computacion"
## [7,] "belleza" "corte" "carpinteria" "chocolateria" "pintura"
## [8,] "chocolateria" "confeccion" "talleres" "carpinteria" "belleza"
## [9,] "dulces" "carpinteria" "ingles" "postres" "pestañas"
## [10,] "postres" "belleza" "dulces" "mesa" "dulces"
# Para visualizar las palabras clave en todo el texto de los 4 archivos
print(terms_lda_ALL)
## Topic 1 Topic 2 Topic 3 Topic 4 Topic 5
## [1,] "reposteria" "bien" "excelente" "bien" "ninguno"
## [2,] "piñatas" "excelente" "bueno" "bueno" "ingles"
## [3,] "taller" "buenos" "bien" "taller" "reposteria"
## [4,] "ingles" "ninguno" "maestra" "ninguno" "bien"
## [5,] "uñas" "taller" "buen" "excelente" "cocina"
## [6,] "pasta" "buen" "buena" "buen" "carpinteria"
## [7,] "belleza" "maestra" "ninguno" "maestra" "belleza"
## [8,] "panaderia" "bueno" "exelente" "exelente" "musica"
## [9,] "flexible" "satisfecho" "taller" "buenos" "corte"
## [10,] "pintura" "buena" "falta" "niños" "computacion"
# Gráficas de los 5 tópicos principales en todo el texto de los 4 archivos
lda_tidy_ALL <- tidy(lda_model_ALL)
top_terms_ALL <- lda_tidy_ALL %>%
group_by(topic) %>%
slice_max(beta, n = 10) %>%
ungroup() %>%
arrange(topic, -beta)
ggplot(top_terms_ALL, aes(x = reorder_within(term, beta, topic), y = beta, fill = factor(topic))) +
geom_col(show.legend = FALSE) +
facet_wrap(~ topic, scales = "free", ncol = 3) +
scale_x_reordered() +
theme_minimal() +
labs(
title = "Principales términos por tópico",
x = "Término",
y = "Beta (Importancia del término)"
) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
El análisis conjunto de las palabras clave, los tópicos y las variables sociodemográficas revela un patrón coherente entre el perfil de los participantes y los intereses formativos identificados. La predominancia femenina en los cursos comunitarios, acompañada de un nivel educativo medio y una ocupación centrada en el hogar, se vincula directamente con los temas más mencionados, como belleza, repostería, confección y bienestar físico. Esto indica que los talleres funcionan como espacios de capacitación práctica y empoderamiento económico, donde las mujeres encuentran oportunidades para emprender o complementar ingresos familiares.
Asimismo, la presencia de palabras y tópicos relacionados con inglés, computación, pintura o música muestra un interés por ampliar habilidades culturales y tecnológicas, reflejando una motivación de aprendizaje continuo y superación personal. La distribución territorial de los centros como San Bernabé, Monte Kristal y Santa Fe evidencia una participación activa en zonas urbanas populares, donde los talleres representan también espacios de convivencia, integración comunitaria y bienestar emocional. Finalmente, la aplicación del aprendizaje en los ámbitos personal, familiar y laboral confirma que el impacto de los cursos trasciende lo educativo, generando beneficios sociales y económicos sostenibles dentro de las comunidades.
Los datos muestran que la participación en los centros comunitarios es principalmente femenina, con mujeres adultas, casadas y con nivel educativo medio. Los talleres más cursados (Belleza, Zumba, Corte y Confección, Piñatas) reflejan una orientación hacia actividades prácticas y de bienestar, aunque también existe interés creciente por áreas técnicas y culturales como inglés o computación.Esta tendencia sugiere que los cursos funcionan como espacios de aprendizaje, convivencia y empoderamiento económico, pero también que pueden reproducir patrones tradicionales de género.En la siguiente etapa se analizará la relación entre género, escolaridad y tipo de taller cursado, para identificar si existe segregación formativa y cómo se vincula con la estructura ocupacional de Nuevo León.
Análisis descriptivo del perfil de los participantes: Explorar la distribución de género, estado civil, nivel educativo y ocupación entre quienes toman los talleres. Esto permitiría ver si existen patrones demográficos marcados (por ejemplo, más mujeres casadas en talleres de oficios domésticos o más hombres solteros en talleres técnicos).
Asociación entre género y tipo de taller cursado: Identificar si existe una segregación por género en la elección del taller (por ejemplo, mujeres en repostería o manualidades, hombres en carpintería o computación).
Influencia de escolaridad y ocupación actual: Analizar si la formación previa y la posición laboral condicionan la elección del taller.
Vínculo con la segregación ocupacional en Nuevo León: Relacionar los resultados de los talleres con datos externos sobre la estructura ocupacional del estado, mostrando cómo los patrones de elección reflejan o refuerzan la segregación laboral por género en la región.
Enfoque interseccional: Integrar variables como género, estado civil y ocupación para analizar cómo la combinación de factores influye en la elección del taller. Por ejemplo, mujeres casadas con hijos podrían mostrar preferencias distintas a mujeres solteras, o hombres desempleados podrían optar por talleres distintos a hombres empleados.