citas <- read.csv("appointments.csv", stringsAsFactors = FALSE)
citas <- citas %>%
mutate(appointment_date = as.Date(appointment_date),
hora = as.integer(substr(appointment_time, 1, 2)),
franja = ifelse(hora < 12, "Mañana", "Tarde"),
sex = factor(sex),
status = factor(status))
# Subconjuntos según la pregunta de gestión:
atendidas <- citas %>% filter(status == "attended") # tienen tiempo de espera
efectivas <- citas %>% filter(status %in% c("attended", "did not attend")) # citas que "debían ocurrir"
dim(citas)
## [1] 111488 18
Qué es cada subconjunto: el tiempo de espera
(waiting_time, en minutos) solo existe si el paciente fue
atendido. Las inasistencias solo se pueden evaluar sobre citas que no
fueron canceladas con anticipación.
sample()El espacio muestral (conjunto de todos los resultados posibles) de una cita es el conjunto de sus estados. Un evento es un resultado o grupo de resultados de interés (por ejemplo, “el paciente no asiste”).
# (a) Muestra aleatoria de 500 citas para una auditoría de calidad
muestra <- citas[sample(nrow(citas), size = 500), ]
c(edad_base = mean(citas$age), edad_muestra = mean(muestra$age))
## edad_base edad_muestra
## 57.20521 56.50800
# (b) Simular 1000 citas con las probabilidades reales de cada estado
espacio <- levels(citas$status)
p_real <- as.numeric(prop.table(table(citas$status)))
sim <- sample(espacio, size = 1000, replace = TRUE, prob = p_real)
# Evento A = "no asiste" ; probabilidad simulada vs. real
c(simulada = mean(sim == "did not attend"),
real = mean(citas$status == "did not attend"))
## simulada real
## 0.05900000 0.05933374
Interpretación: la muestra aleatoria de 500 citas reproduce bien las características de la base completa (la edad promedio es casi igual), lo que justifica auditar con muestras en lugar de revisar todas las citas. En la simulación, la frecuencia de “no asiste” se acerca a la real (≈ 5,9 % de todas las citas), pero no es idéntica: esa diferencia es variación del azar y disminuye al aumentar el número de simulaciones (ley de los grandes números).
table()Una probabilidad empírica es la frecuencia relativa observada: casos del evento / casos totales.
# Probabilidad de cada estado de la cita
round(prop.table(table(citas$status)), 4)
##
## attended cancelled did not attend scheduled unknown
## 0.7717 0.1637 0.0593 0.0013 0.0040
# Probabilidad condicional: P(no asiste | sexo), sobre citas efectivas
tab_sexo <- table(efectivas$sex, efectivas$status)[, c("attended", "did not attend")]
round(prop.table(tab_sexo, margin = 1), 4)
##
## attended did not attend
## Female 0.9291 0.0709
## Male 0.9279 0.0721
# Probabilidad condicional: P(espera > 30 min | franja horaria)
tab_espera <- table(atendidas$franja, atendidas$waiting_time > 30)
round(prop.table(tab_espera, margin = 1), 4)
##
## FALSE TRUE
## Mañana 0.6376 0.3624
## Tarde 0.3458 0.6542
Interpretación: aproximadamente 77 % de las citas se atienden, 16 % se cancelan y 6 % son inasistencias. La probabilidad de no asistir es prácticamente la misma en mujeres y hombres (≈ 7 % de las citas efectivas), por lo que el sexo no ayuda a priorizar llamadas de recordatorio. En cambio, la probabilidad de esperar más de 30 minutos es muy distinta según la franja: ≈ 36 % en la mañana frente a ≈ 65 % en la tarde. Condicional significa “dado que ocurre otra cosa” (por ejemplo, dado que la cita es en la tarde).
runif(),
rbinom() y dpois()a) runif() (uniforme: todos los valores igual de
probables) para un sorteo de auditoría.
# Se audita ~20 % de las historias: cada cita recibe un número al azar entre 0 y 1
sorteo <- runif(nrow(atendidas))
auditar <- sorteo < 0.20
c(auditadas = sum(auditar), proporcion = mean(auditar))
## auditadas proporcion
## 1.709400e+04 1.986935e-01
b) rbinom() (binomial: número de “éxitos” en n
intentos) para inasistencias diarias. La agenda tiene ≈ 43
citas por día y la probabilidad de inasistencia por cita es ≈ 0,059.
n_dia <- round(nrow(citas) / n_distinct(citas$appointment_date)) # citas por día
p_ns <- mean(citas$status == "did not attend")
inasist_sim <- rbinom(n = 365, size = n_dia, prob = p_ns) # un año simulado
table(inasist_sim)
## inasist_sim
## 0 1 2 3 4 5 6 7 8
## 27 77 107 72 43 30 5 3 1
c(media_sim = mean(inasist_sim), media_teorica = n_dia * p_ns)
## media_sim media_teorica
## 2.432877 2.551351
c) dpois() (Poisson: conteo de eventos por
unidad de tiempo) para cancelaciones por día. Se compara con lo
observado.
canc_dia <- citas %>%
group_by(appointment_date) %>%
summarise(cancel = sum(status == "cancelled"))
lambda <- mean(canc_dia$cancel) # promedio de cancelaciones por día
comparacion <- data.frame(
cancelaciones = 0:15,
observada = as.numeric(prop.table(table(factor(canc_dia$cancel, levels = 0:15)))),
poisson = dpois(0:15, lambda)
)
round(comparacion, 3)
## cancelaciones observada poisson
## 1 0 0.005 0.001
## 2 1 0.005 0.006
## 3 2 0.023 0.022
## 4 3 0.046 0.052
## 5 4 0.085 0.091
## 6 5 0.131 0.127
## 7 6 0.158 0.149
## 8 7 0.139 0.149
## 9 8 0.135 0.131
## 10 9 0.101 0.102
## 11 10 0.078 0.071
## 12 11 0.043 0.045
## 13 12 0.022 0.027
## 14 13 0.019 0.014
## 15 14 0.007 0.007
## 16 15 0.003 0.003
# P(un día tenga 12 o más cancelaciones): día "crítico" para la agenda
1 - ppois(11, lambda)
## [1] 0.05380193
Interpretación: en un año típico se esperan ≈ 2,5 inasistencias por día, pero la simulación muestra que hay días con 0 y días con 6 o más: el promedio esconde variación. Las cancelaciones diarias observadas (media ≈ 7) siguen muy de cerca la Poisson, lo cual indica que ocurren de forma independiente y sin patrón especial. Esto sirve para dimensionar el sobreagendamiento (citar más pacientes que cupos) y para saber cuándo un día es realmente atípico.
rexp(), dexp(), pexp())La exponencial describe tiempos hasta que ocurre algo y es muy asimétrica (muchos valores bajos, pocos muy altos). El tiempo de espera real tiene media ≈ 44 min y desviación ≈ 41 min (casi iguales, característica de la exponencial).
media_esp <- mean(atendidas$waiting_time)
tasa <- 1 / media_esp
esp_sim <- rexp(10000, rate = tasa) # tiempos simulados
# Probabilidad teórica vs. real de esperar más de 30 y de 60 minutos
data.frame(
umbral_min = c(30, 60),
teorica = 1 - pexp(c(30, 60), rate = tasa),
real = c(mean(atendidas$waiting_time > 30), mean(atendidas$waiting_time > 60))
)
## umbral_min teorica real
## 1 30 0.5063737 0.5375325
## 2 60 0.2564144 0.2784778
Interpretación: el modelo exponencial estima 51 % de pacientes esperando más de 30 minutos y 26 % más de 60; en los datos reales son 54 % y 28 %. El modelo es una aproximación razonable, aunque subestima ligeramente las esperas largas. Para la gestión, una cuarta parte de los pacientes espera más de una hora.
rnorm(), dnorm(), pnorm())La normal tiene forma de campana. Aunque la espera individual no es normal, el promedio de esperas de un grupo de pacientes sí tiende a serlo (teorema del límite central). Ejemplo: el promedio de espera de un turno de 30 pacientes.
# Promedios de 10.000 turnos de 30 pacientes elegidos al azar
prom_turno <- replicate(10000, mean(sample(atendidas$waiting_time, 30)))
mu <- mean(atendidas$waiting_time)
ee <- sd(atendidas$waiting_time) / sqrt(30) # error estándar (variación esperada del promedio)
c(media_simulada = mean(prom_turno), sd_simulada = sd(prom_turno), error_estandar = ee)
## media_simulada sd_simulada error_estandar
## 44.068661 7.474506 7.446980
# P(que el promedio de un turno supere 55 minutos)
1 - pnorm(55, mean = mu, sd = ee)
## [1] 0.07139334
# Simulación directa con rnorm (para comparar): mismos parámetros
head(rnorm(5, mean = mu, sd = ee))
## [1] 45.02815 43.14960 38.05771 34.57859 33.89320
Interpretación: los promedios por turno se centran en ≈ 44 min con una variación de ≈ 7 min. Que un turno de 30 pacientes tenga un promedio mayor a 55 min es poco probable (≈ 7 %) si la agenda fuera homogénea; como en la práctica los turnos de la tarde sí superan ese valor (sección 2.5), la causa no es el azar sino la organización de la agenda.
runif())hora_sim <- runif(nrow(citas), min = 8, max = 18) # horas entre 8:00 y 18:00
hora_real <- citas$hora + as.numeric(substr(citas$appointment_time, 4, 5)) / 60
data.frame(
P_antes_12 = c(simulada = mean(hora_sim < 12), real = mean(hora_real < 12)),
P_despues_16 = c(mean(hora_sim >= 16), mean(hora_real >= 16))
)
## P_antes_12 P_despues_16
## simulada 0.4009490 0.1990169
## real 0.4005812 0.1999229
Interpretación: las citas están repartidas de forma casi uniforme durante el día (≈ 40 % antes de las 12:00). Esto es importante: la carga de cupos es pareja, así que el aumento de la espera en la tarde no se explica por más citas, sino por el retraso acumulado a lo largo de la jornada.
g1 <- ggplot(data.frame(inasistencias = inasist_sim), aes(x = inasistencias)) +
geom_bar(fill = "steelblue") +
labs(title = "Inasistencias diarias simuladas (binomial, 1 año)",
x = "Inasistencias en el día", y = "Número de días") +
theme_minimal()
ggplotly(g1)
g2 <- ggplot(comparacion, aes(x = cancelaciones)) +
geom_col(aes(y = observada), fill = "grey70") +
geom_line(aes(y = poisson), color = "red", linewidth = 1) +
geom_point(aes(y = poisson), color = "red") +
labs(title = "Cancelaciones por día: observado (barras) vs. Poisson (rojo)",
x = "Cancelaciones en el día", y = "Probabilidad") +
theme_minimal()
ggplotly(g2)
Gráfico 1. Inasistencias diarias simuladas
El gráfico muestra la distribución del número de inasistencias diarias durante un año simulado. La mayor frecuencia corresponde a los días con aproximadamente dos inasistencias, seguidos de los días con una y tres. A medida que aumenta el número de inasistencias, disminuye la cantidad de días observados.
Análisis: La distribución indica que las inasistencias bajas o moderadas son más frecuentes que aquellas con valores elevados. Sin embargo, se presentan días con seis o más inasistencias, lo que puede representar una pérdida importante de capacidad de atención. En una IPS, este comportamiento puede generar espacios de agenda desaprovechados, menor productividad y dificultades para cumplir las metas de atención.
Conclusión: Es conveniente implementar estrategias de confirmación de citas, recordatorios previos y reasignación oportuna de los cupos disponibles. Estas medidas permitirían reducir la pérdida de capacidad instalada y mejorar el acceso de los pacientes. Como los datos son simulados, los resultados no deben interpretarse como evidencia de un comportamiento real de una institución.
Gráfico 2. Cancelaciones observadas frente a la distribución de Poisson
El gráfico compara la frecuencia observada de cancelaciones diarias con una curva teórica de distribución de Poisson. La mayor probabilidad se concentra aproximadamente entre cinco y siete cancelaciones por día, mientras que los valores muy bajos o muy altos presentan menor probabilidad.
Análisis: La curva roja representa el comportamiento esperado bajo un modelo de Poisson, utilizado para estudiar la frecuencia de eventos en un intervalo determinado. La proximidad entre las barras y la curva sugiere que el modelo podría describir razonablemente el patrón general de cancelaciones. No obstante, la representación gráfica por sí sola no permite confirmar un ajuste estadístico adecuado. En una IPS, conocer el comportamiento habitual de las cancelaciones permite estimar la demanda efectiva, planificar la disponibilidad de profesionales y establecer mecanismos para cubrir los cupos liberados.
Conclusión: Se recomienda analizar las causas de las cancelaciones, identificar los días con mayor frecuencia y establecer listas de pacientes para reasignar las citas. Para confirmar la pertinencia del modelo de Poisson, se deben contrastar los datos observados con los valores esperados mediante pruebas estadísticas.
g3 <- ggplot(atendidas, aes(x = waiting_time)) +
geom_histogram(aes(y = after_stat(density)), bins = 40, fill = "grey80", color = "white") +
stat_function(fun = dexp, args = list(rate = tasa), color = "red", linewidth = 1) +
labs(title = "Tiempo de espera real vs. curva exponencial",
x = "Minutos de espera", y = "Densidad") +
theme_minimal()
ggplotly(g3)
g4 <- ggplot(data.frame(prom = prom_turno), aes(x = prom)) +
geom_histogram(aes(y = after_stat(density)), bins = 40, fill = "skyblue", color = "white") +
stat_function(fun = dnorm, args = list(mean = mu, sd = ee), color = "red", linewidth = 1) +
labs(title = "Promedio de espera por turno de 30 pacientes (normal)",
x = "Promedio de espera (min)", y = "Densidad") +
theme_minimal()
ggplotly(g4)
Comentario: pase el cursor sobre las barras para ver valores exactos. La espera individual es muy asimétrica (g3), pero el promedio por turno es simétrico y se ajusta a la campana (g4): es la razón por la que se pueden usar pruebas basadas en la normal para comparar medias aunque los datos individuales no sean normales (con muestras grandes).
Gráfico 3. Tiempo de espera real frente a curva exponencial
El gráfico presenta la distribución de los tiempos de espera reales y una curva exponencial de referencia. Se observa una mayor concentración de esperas cortas y una disminución progresiva de la frecuencia a medida que aumenta el tiempo. También aparecen esperas prolongadas que alcanzan aproximadamente los 300 minutos.
Análisis: La distribución muestra una asimetría hacia la derecha: la mayoría de los tiempos se concentra en valores bajos, pero algunos pacientes experimentan demoras considerablemente mayores. Esto significa que un promedio general podría ocultar situaciones críticas de espera. Además, la curva roja no parece ajustarse adecuadamente a toda la distribución observada, por lo que no debe asumirse que el modelo exponencial representa fielmente los datos. En una IPS, las esperas prolongadas pueden afectar la satisfacción del usuario, la oportunidad de atención y la percepción de calidad del servicio.
Conclusión: Es necesario identificar las causas de las demoras extremas y analizar indicadores como la mediana, el percentil 90 y el porcentaje de pacientes atendidos dentro del tiempo establecido. Esto permitiría detectar problemas de capacidad, asignación de citas o flujo de pacientes.
Gráfico 4. Promedio de espera por turno de 30 pacientes
El histograma presenta la distribución de los promedios de espera calculados para turnos de 30 pacientes. La mayor concentración se encuentra aproximadamente entre los 35 y 50 minutos, con un comportamiento relativamente simétrico y una forma similar a una distribución normal.
Análisis: El gráfico sugiere que los promedios de espera de los turnos tienden a concentrarse alrededor de un valor central, con menor frecuencia de promedios muy bajos o muy altos. Este comportamiento puede explicarse porque, al calcular promedios de grupos de pacientes, las variaciones individuales tienden a compensarse parcialmente.
Sin embargo, el gráfico no permite establecer por sí solo cuál es el promedio exacto ni confirmar que los tiempos de espera individuales sigan una distribución normal. Tampoco demuestra que la espera sea aceptable desde el punto de vista de la calidad asistencial.
Conclusión: Analizar los promedios por turnos permite identificar la estabilidad del proceso de atención y detectar jornadas con demoras superiores a las habituales. Se recomienda complementar este análisis con metas institucionales de oportunidad y con la evaluación de los tiempos individuales.
indicadores <- atendidas %>% select(waiting_time, appointment_duration, scheduling_interval, age)
resumen <- data.frame(
media = sapply(indicadores, mean),
mediana = sapply(indicadores, median),
desv_est = sapply(indicadores, sd),
varianza = sapply(indicadores, var),
minimo = sapply(indicadores, function(x) range(x)[1]),
maximo = sapply(indicadores, function(x) range(x)[2])
)
round(resumen, 2)
## media mediana desv_est varianza minimo maximo
## waiting_time 44.09 33.5 40.79 1663.73 0.6 297.3
## appointment_duration 17.48 15.8 11.06 122.42 0.0 58.7
## scheduling_interval 7.20 5.0 6.16 37.95 1.0 30.0
## age 57.23 59.0 20.15 406.10 15.0 100.0
summary(atendidas$waiting_time)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.60 12.60 33.50 44.09 64.60 297.30
atendidas %>%
group_by(franja) %>%
summarise(n = n(), media = mean(waiting_time), mediana = median(waiting_time),
desv_est = sd(waiting_time), rango_min = min(waiting_time),
rango_max = max(waiting_time)) %>%
mutate(across(where(is.numeric), ~ round(.x, 1)))
## # A tibble: 2 × 7
## franja n media mediana desv_est rango_min rango_max
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Mañana 34388 27.2 20.7 25.9 0.6 215.
## 2 Tarde 51644 55.3 46.7 44.8 0.6 297.
Interpretación: la espera tiene media ≈ 44 min y mediana ≈ 33,5 min. Cuando la media es mayor que la mediana, hay pocos pacientes con esperas muy largas que “jalan” el promedio (el máximo llega a ≈ 297 min). Para informar el indicador es más representativa la mediana. La desviación estándar (cuánto se alejan los datos del promedio; ≈ 41 min) es casi tan grande como la media: la experiencia del paciente es muy desigual. Por franja, la espera en la mañana (media ≈ 27 min) es la mitad que en la tarde (≈ 55 min). La duración de la consulta (media ≈ 17,5 min) casi no varía entre franjas, así que la diferencia se origina en la acumulación de retrasos y no en consultas más largas.
Regla de lectura: si el valor p < 0,05, la diferencia observada es estadísticamente significativa (es poco probable que se deba solo al azar). Un intervalo de confianza (IC) del 95 % es el rango donde, con 95 % de confianza, está el valor real de la población.
t.test())# Comparar medias de espera entre dos grupos
t.test(waiting_time ~ franja, data = atendidas)
##
## Welch Two Sample t-test
##
## data: waiting_time by franja
## t = -116.52, df = 84536, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group Mañana and group Tarde is not equal to 0
## 95 percent confidence interval:
## -28.63336 -27.68599
## sample estimates:
## mean in group Mañana mean in group Tarde
## 27.18258 55.34226
# IC 95 % para la espera promedio general
t.test(atendidas$waiting_time)$conf.int
## [1] 43.81395 44.35907
## attr(,"conf.level")
## [1] 0.95
# Comparación sin diferencia esperada: duración de la consulta por sexo
t.test(appointment_duration ~ sex, data = atendidas)
##
## Welch Two Sample t-test
##
## data: appointment_duration by sex
## t = 0.20951, df = 75072, p-value = 0.834
## alternative hypothesis: true difference in means between group Female and group Male is not equal to 0
## 95 percent confidence interval:
## -0.1344449 0.1666282
## sample estimates:
## mean in group Female mean in group Male
## 17.48606 17.46997
Interpretación: la espera promedio es ≈ 27 min en la mañana y ≈ 55 min en la tarde; el valor p es prácticamente 0 y el IC de la diferencia (≈ −28,6 a −27,7 min) no incluye el cero: la diferencia es significativa y de magnitud relevante (la tarde espera el doble). En cambio, la duración de la consulta entre mujeres y hombres (≈ 17,5 min en ambos) no es significativa (p alto): el problema no está en cuánto dura la consulta según el paciente.
aov())El ANOVA compara las medias de tres o más grupos a la vez.
atendidas$hora_f <- factor(atendidas$hora)
anova_hora <- aov(waiting_time ~ hora_f, data = atendidas)
summary(anova_hora)
## Df Sum Sq Mean Sq F value Pr(>F)
## hora_f 9 21722581 2413620 1710 <2e-16 ***
## Residuals 86022 121409384 1411
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Comparaciones por pares: ¿qué horas difieren entre sí?
head(TukeyHSD(anova_hora)$hora_f, 10)
## diff lwr upr p adj
## 9-8 8.329033 6.516732 10.141333 0
## 10-8 15.638931 13.825305 17.452556 0
## 11-8 21.838921 20.028358 23.649483 0
## 12-8 27.992344 26.180413 29.804275 0
## 13-8 32.809873 30.997255 34.622491 0
## 14-8 37.559677 35.747218 39.372137 0
## 15-8 42.287702 40.477034 44.098369 0
## 16-8 46.672075 44.860250 48.483901 0
## 17-8 50.222852 48.414641 52.031064 0
## 10-9 7.309898 5.494800 9.124996 0
# Contraste: grupo de edad
anova_edad <- aov(waiting_time ~ age_group, data = atendidas)
summary(anova_edad)
## Df Sum Sq Mean Sq F value Pr(>F)
## age_group 15 38444 2563 1.541 0.0819 .
## Residuals 86016 143093521 1664
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Interpretación: la espera cambia de forma significativa según la hora (valor p ≈ 0): crece de ≈ 16 min a las 8:00 hasta ≈ 66 min a las 17:00, de manera progresiva. La prueba de Tukey (comparación de cada par de horas) confirma que casi todas las horas difieren entre sí. Por grupo de edad no hay diferencia significativa (p ≈ 0,08 > 0,05): no hay evidencia de que se esté atendiendo con más demora a adultos mayores ni a jóvenes. Intervenir sobre los grupos de edad no reduciría la espera; intervenir sobre la programación horaria sí.
chisq.test())La prueba chi-cuadrado evalúa si dos variables categóricas están relacionadas o son independientes.
# ¿El estado de la cita depende del sexo? (se excluyen estados con muy pocos casos)
tab1 <- table(citas$sex, citas$status)[, c("attended", "cancelled", "did not attend")]
tab1
##
## attended cancelled did not attend
## Female 51096 10721 3900
## Male 34936 7533 2715
chisq.test(tab1)
##
## Pearson's Chi-squared test
##
## data: tab1
## X-squared = 2.9761, df = 2, p-value = 0.2258
# ¿La espera larga (>30 min) depende de la franja horaria?
tab2 <- table(atendidas$franja, atendidas$waiting_time > 30)
chisq.test(tab2)
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: tab2
## X-squared = 7067.3, df = 1, p-value < 2.2e-16
Interpretación: el estado de la cita (atendida, cancelada, inasistencia) no está asociado al sexo (p ≈ 0,1 > 0,05): no hay evidencia de que mujeres y hombres cancelen o falten de forma distinta. La espera mayor a 30 minutos sí está fuertemente asociada con la franja horaria (p ≈ 0). La ausencia de asociación también es un hallazgo útil: evita diseñar estrategias de recordatorio por sexo.
prop.test())# Proporción de pacientes con espera > 30 min: mañana vs. tarde
x <- tapply(atendidas$waiting_time > 30, atendidas$franja, sum) # pacientes con espera larga
n <- tapply(atendidas$waiting_time > 30, atendidas$franja, length)
prop.test(x, n)
##
## 2-sample test for equality of proportions with continuity correction
##
## data: x out of n
## X-squared = 7067.3, df = 1, p-value < 2.2e-16
## alternative hypothesis: two.sided
## 95 percent confidence interval:
## -0.2983118 -0.2852035
## sample estimates:
## prop 1 prop 2
## 0.3623939 0.6541515
# Proporción de inasistencia (sobre citas efectivas): mujeres vs. hombres
x2 <- tapply(efectivas$status == "did not attend", efectivas$sex, sum)
n2 <- tapply(efectivas$status == "did not attend", efectivas$sex, length)
prop.test(x2, n2)
##
## 2-sample test for equality of proportions with continuity correction
##
## data: x2 out of n2
## X-squared = 0.46383, df = 1, p-value = 0.4958
## alternative hypothesis: two.sided
## 95 percent confidence interval:
## -0.004598407 0.002207627
## sample estimates:
## prop 1 prop 2
## 0.07091425 0.07210964
Interpretación: la proporción de pacientes con espera mayor a 30 min es ≈ 36 % en la mañana y ≈ 65 % en la tarde; la diferencia (≈ 29 puntos porcentuales) es significativa y su IC no incluye el cero. La proporción de inasistencia entre mujeres y hombres (≈ 7,1 % vs. 7,2 %) no difiere de forma significativa. Conclusión de gestión: la inasistencia no es el problema que diferencia a los grupos; la oportunidad de mejora está en la programación de la tarde.
ggpubrp1 <- ggboxplot(atendidas, x = "franja", y = "waiting_time",
fill = "franja", palette = c("#2E86C1", "#E67E22"),
xlab = "Franja horaria", ylab = "Espera (min)",
title = "Tiempo de espera por franja")
ggplotly(p1)
Gráfico 5. Tiempo de espera según franja horaria
El diagrama de cajas compara los tiempos de espera durante la mañana y la tarde. Se observa que la mediana y la dispersión de los tiempos son mayores en la tarde. Además, ambas franjas presentan valores atípicos, aunque los más elevados aparecen en la jornada de la tarde.
Análisis: Los resultados sugieren que los pacientes atendidos en la tarde experimentan mayores tiempos de espera y una variabilidad más amplia. Esto puede indicar diferencias en la demanda, disponibilidad de profesionales, duración de las consultas o acumulación de retrasos durante la jornada. Sin embargo, el gráfico no permite determinar cuál de estos factores explica la diferencia. Los valores atípicos reflejan pacientes con esperas considerablemente superiores a las habituales, lo que requiere revisar las causas específicas y su posible impacto en la experiencia del usuario.
Conclusión: La IPS debería comparar la demanda y la capacidad de atención de ambas jornadas, revisar el cumplimiento de los horarios y evaluar la redistribución de recursos hacia la tarde si los datos operativos confirman una mayor congestión.
p2 <- ggline(atendidas, x = "hora", y = "waiting_time",
add = "mean_se", color = "darkred",
xlab = "Hora de la cita", ylab = "Espera promedio (min)",
title = "La espera aumenta a lo largo del día")
ggplotly(p2)
Gráfico 6. Incremento del tiempo de espera a lo largo del día La gráfica muestra una tendencia ascendente del tiempo promedio de espera conforme avanza la hora de la cita. El valor pasa de aproximadamente 16 minutos a las 8:00 a. m. a cerca de 66 minutos a las 4:00 p. m.
Análisis: El comportamiento evidencia una acumulación progresiva de las demoras durante la jornada. Esto puede ocurrir cuando los retrasos de las primeras consultas se trasladan a las siguientes, especialmente si la duración real de la atención supera el tiempo asignado en la agenda o si se presentan interrupciones operativas.
La tendencia es relevante porque sugiere que la hora de la cita está relacionada con el tiempo de espera promedio. No obstante, el gráfico por sí solo no demuestra una relación causal ni permite establecer si el patrón se mantiene todos los días.
Conclusión: Se recomienda comparar la duración programada y real de las consultas, medir el retraso de inicio de cada profesional y revisar la programación de las citas de la tarde. El objetivo debe ser evitar que las demoras se acumulen y garantizar una atención oportuna durante toda la jornada.
prop_larga <- atendidas %>%
group_by(franja) %>%
summarise(prop = mean(waiting_time > 30) * 100)
p3 <- ggbarplot(prop_larga, x = "franja", y = "prop", fill = "franja",
palette = c("#2E86C1", "#E67E22"),
xlab = "Franja horaria", ylab = "% con espera > 30 min",
title = "Pacientes con espera mayor a 30 minutos")
ggplotly(p3)
Gráfico 7. Porcentaje de pacientes con espera superior a 30 minutos
El gráfico compara la proporción de pacientes que esperan más de 30 minutos según la franja horaria. La mañana presenta aproximadamente un 36 %, mientras que la tarde alcanza cerca del 66 %.
Análisis: La diferencia es cercana a 30 puntos porcentuales, lo que evidencia una mayor proporción de pacientes con esperas prolongadas durante la tarde. En términos prácticos, aproximadamente dos de cada tres pacientes de esa jornada superarían los 30 minutos de espera, frente a poco más de uno de cada tres en la mañana.
Este indicador complementa el análisis del promedio, porque permite identificar directamente qué proporción de usuarios supera un umbral de espera definido. Sin embargo, el límite de 30 minutos debe corresponder a un criterio institucional o de evaluación previamente establecido; el gráfico no demuestra por sí solo que ese sea el estándar normativo aplicable.
Conclusión: La jornada de la tarde debe priorizarse en el análisis de oportunidad. Es necesario identificar las causas de las demoras, establecer acciones correctivas y realizar seguimiento periódico al porcentaje de pacientes que superan los 30 minutos.
ggboxplot(atendidas, x = "franja", y = "waiting_time", fill = "franja",
palette = c("#2E86C1", "#E67E22"), outlier.shape = NA) +
stat_compare_means(method = "t.test", label.y = 150) +
coord_cartesian(ylim = c(0, 160)) +
labs(x = "Franja horaria", y = "Espera (min)")
Gráfico 8. Comparación estadística de los tiempos de espera por franja
horaria El diagrama de cajas compara nuevamente los tiempos de espera de
la mañana y la tarde e incluye el resultado de una prueba t con un valor
de \(p < 2 \times 10^{-16}\).
Análisis: La mediana del tiempo de espera es considerablemente mayor en la tarde que en la mañana. Asimismo, la dispersión de los tiempos es más amplia durante la tarde, lo que indica una mayor variabilidad en la experiencia de los pacientes. El valor de p reportado señala evidencia estadística muy fuerte contra la hipótesis de igualdad de medias, bajo los supuestos de la prueba utilizada. Es importante distinguir la significación estadística de la relevancia operativa: el resultado respalda que existe una diferencia entre las medias, pero no identifica las causas de esa diferencia ni demuestra que la franja horaria sea su causa directa. También es necesario verificar los supuestos de la prueba y la independencia de las observaciones.
Conclusión: Los resultados respaldan la necesidad de intervenir los tiempos de espera de la tarde. Se recomienda complementar la prueba estadística con la magnitud de la diferencia entre medias, su intervalo de confianza y el análisis de los factores operativos que podrían explicar el comportamiento observado.
Comentario: el diagrama de cajas (2.6.1) muestra la mediana y la dispersión: la caja de la tarde está más arriba y es más ancha, es decir, no solo se espera más sino que la experiencia es más impredecible. El gráfico de líneas (2.6.2) muestra el patrón en el tiempo: el incremento es casi lineal (≈ 5 min más de espera por cada hora transcurrida), señal de un retraso que se acumula sin recuperarse. El gráfico de barras (2.6.3) resume el indicador para el seguimiento de calidad: casi dos de cada tres pacientes de la tarde esperan más de 30 minutos. Estos patrones apoyan decisiones concretas como redistribuir cupos, agendar menos pacientes por hora en la tarde o incluir pausas de recuperación en la agenda.