Análisis Exploratorio de Datos (EDA)

Conocimiento y estructura de la base de datos

Importación y reconocimiento de los datos

El Análisis Exploratorio de Datos (EDA) permite conocer la estructura de una base de datos, identificar sus variables, reconocer posibles problemas de calidad y explorar visualmente la información antes de realizar análisis posteriores.

Para este ejercicio se utiliza la base de datos Medical Appointment Scheduling System, relacionada con el proceso de agendamiento de citas médicas.

Primero, cargamos las librerías necesarias:

library(readr)
library(dplyr)
## 
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)
library(plotly)
## 
## Adjuntando el paquete: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
library(knitr)
citas <- read_csv("appointments.csv", show_col_types = FALSE)

A continuación las dimensiones de la base, las primeras columnas y los primeros registros

dim(citas)
## [1] 111488     16
names(citas)
##  [1] "appointment_id"       "slot_id"              "scheduling_date"     
##  [4] "appointment_date"     "appointment_time"     "scheduling_interval" 
##  [7] "status"               "check_in_time"        "appointment_duration"
## [10] "start_time"           "end_time"             "waiting_time"        
## [13] "patient_id"           "sex"                  "age"                 
## [16] "age_group"
head(citas)

Interpretación: la base contiene 111.488 registros y 16 columnas. Cada fila representa un registro de cita y las columnas contienen información relacionada con la programación, el estado de la atención, los tiempos y las características del paciente.

Descripción de las variables

Las variables permiten reconocer qué información se encuentra disponible para estudiar el proceso de agendamiento.

Descripción de las variables
Variable Descripción Tipo de información
appointment_id Identificador único de la cita médica. Identificación
slot_id Identificador del espacio de agenda asignado. Identificación
scheduling_date Fecha en que se programó la cita. Fecha
appointment_date Fecha programada para la atención. Fecha
appointment_time Hora programada para la cita. Hora
scheduling_interval Número de días entre la programación y la fecha de atención. Numérica
status Estado registrado de la cita médica. Categórica
check_in_time Hora de llegada o registro del paciente. Hora
appointment_duration Duración registrada de la atención, en minutos. Numérica
start_time Hora real de inicio de la atención. Hora
end_time Hora real de finalización de la atención. Hora
waiting_time Tiempo de espera registrado, en minutos. Numérica
patient_id Identificador del paciente. Identificación
sex Sexo registrado del paciente. Categórica
age Edad del paciente en años. Numérica
age_group Categoría o grupo de edad del paciente. Categórica

La clasificación anterior se refiere al contenido de las variables. En R, las fechas y horas pueden importarse como texto, por lo que también es necesario revisar cómo están almacenadas realmente.

Consultamos la estructura reconocida por R:

str(citas)
## spc_tbl_ [111,488 × 16] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ appointment_id      : chr [1:111488] "0000138" "0000146" "0000021" "0000233" ...
##  $ slot_id             : chr [1:111488] "0000001" "0000023" "0000024" "0000025" ...
##  $ scheduling_date     : Date[1:111488], format: "2014-12-28" "2014-12-29" ...
##  $ appointment_date    : Date[1:111488], format: "2015-01-01" "2015-01-01" ...
##  $ appointment_time    : 'hms' num [1:111488] 08:00:00 13:30:00 13:45:00 14:00:00 ...
##   ..- attr(*, "units")= chr "secs"
##  $ scheduling_interval : num [1:111488] 4 3 15 1 6 2 2 2 4 4 ...
##  $ status              : chr [1:111488] "did not attend" "did not attend" "attended" "attended" ...
##  $ check_in_time       : 'hms' num [1:111488] NA NA 13:36:45 13:59:32 ...
##   ..- attr(*, "units")= chr "secs"
##  $ appointment_duration: num [1:111488] NA NA 5.2 28.9 NA 7.7 4.2 27.1 NA 1.2 ...
##  $ start_time          : 'hms' num [1:111488] NA NA 13:37:57 14:00:40 ...
##   ..- attr(*, "units")= chr "secs"
##  $ end_time            : 'hms' num [1:111488] NA NA 13:43:09 14:29:34 ...
##   ..- attr(*, "units")= chr "secs"
##  $ waiting_time        : num [1:111488] NA NA 1.2 1.1 NA 21.7 16.2 1 NA 8.5 ...
##  $ patient_id          : chr [1:111488] "08285" "05972" "06472" "05376" ...
##  $ sex                 : chr [1:111488] "Male" "Male" "Male" "Female" ...
##  $ age                 : num [1:111488] 37 84 77 37 72 51 28 33 29 90 ...
##  $ age_group           : chr [1:111488] "35-39" "80-84" "75-79" "35-39" ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   appointment_id = col_character(),
##   ..   slot_id = col_character(),
##   ..   scheduling_date = col_date(format = ""),
##   ..   appointment_date = col_date(format = ""),
##   ..   appointment_time = col_time(format = ""),
##   ..   scheduling_interval = col_double(),
##   ..   status = col_character(),
##   ..   check_in_time = col_time(format = ""),
##   ..   appointment_duration = col_double(),
##   ..   start_time = col_time(format = ""),
##   ..   end_time = col_time(format = ""),
##   ..   waiting_time = col_double(),
##   ..   patient_id = col_character(),
##   ..   sex = col_character(),
##   ..   age = col_double(),
##   ..   age_group = col_character()
##   .. )
##  - attr(*, "problems")=<pointer: 0x000001aab34e0150>

Interpretación: esta revisión permite identificar si las variables están almacenadas en un formato apropiado. Por ejemplo, las fechas pueden requerir conversión antes de utilizarlas en gráficos temporales

Exploración visual de los datos

Distribución de las citas según su estado

Este gráfico permite explorar cómo se distribuyen los registros entre los diferentes estados de las citas.

grafico_estados <- citas %>%
  count(status, name = "Cantidad") %>%
  ggplot(aes(x = status, y = Cantidad, fill = status)) +
  geom_col() +
  labs(
    title = "Citas registradas según su estado",
    x = "Estado de la cita",
    y = "Número de registros"
  ) +
  theme_minimal() +
  theme(legend.position = "none")

ggplotly(grafico_estados)

Comentario del gráfico:

La visualización permite identificar cuáles estados concentran más registros y cuáles tienen menor presencia en la base.

Desde la perspectiva de gestión de la calidad, esta información ayuda a reconocer cómo se distribuyen los registros del proceso de agendamiento. Sin embargo, la cantidad de registros de cada estado no equivale automáticamente a una tasa de inasistencia, cancelación o cumplimiento. Para calcular esos indicadores se requiere definir previamente el denominador y las reglas de clasificación correspondientes.

Comportamiento temporal de las citas programadas

Este gráfico permite explorar cómo cambia el número de citas según el mes de atención.

Primero, convertimos la fecha de la cita a un formato que R pueda reconocer:

citas <- citas %>%
  mutate(
    appointment_date = as.Date(appointment_date)
  )

Agrupamos los registros por mes:

citas_mes <- citas %>%
  filter(!is.na(appointment_date)) %>%
  mutate(
    mes = as.Date(
      format(appointment_date, "%Y-%m-01")
    )
  ) %>%
  count(mes, name = "Cantidad")

Construimos el gráfico interactivo:

grafico_temporal <- ggplot(
  citas_mes,
  aes(x = mes, y = Cantidad)
) +
  geom_line() +
  geom_point() +
  labs(
    title = "Registros de citas por mes de atención",
    x = "Mes de atención",
    y = "Número de registros"
  ) +
  theme_minimal()

ggplotly(grafico_temporal)

Comentario del gráfico:

La visualización permite identificar periodos con mayor o menor cantidad de citas registradas y observar cambios en el comportamiento temporal de la agenda.

Desde la gerencia clínica, esta exploración puede orientar revisiones posteriores sobre la organización de la capacidad instalada y la programación de los servicios.

Es importante tener en cuenta que el gráfico representa las citas por fecha de atención, no por fecha de programación. Además, una variación en el número de registros no demuestra por sí sola un aumento o una disminución de la demanda real.

Distribución de los registros por grupo de edad

Este gráfico permite visualizar la distribución de las citas entre los grupos de edad definidos en la base.

grafico_edad <- citas %>%
  filter(!is.na(age_group)) %>%
  count(age_group, name = "Cantidad") %>%
  ggplot(
    aes(
      x = reorder(age_group, age_group),
      y = Cantidad,
      text = paste(
        "Grupo de edad:", age_group,
        "<br>Registros:", Cantidad
      )
    )
  ) +
  geom_col() +
  coord_flip() +
  labs(
    title = "Registros de citas por grupo de edad",
    x = "Grupo de edad",
    y = "Número de registros"
  ) +
  theme_minimal()

ggplotly(grafico_edad, tooltip = "text")

Integración de los hallazgos del EDA

Síntesis del reconocimiento de la base

La exploración inicial permite reconocer la estructura de la base de datos, identificar las variables disponibles, revisar los valores faltantes y visualizar el comportamiento de los registros según el estado de la cita, el mes de atención y el grupo de edad.

Estos elementos proporcionan una primera aproximación al funcionamiento del sistema de agendamiento y permiten reconocer aspectos que requieren revisión antes de desarrollar análisis posteriores.

Desde la gerencia de la calidad y la gestión clínica, el EDA constituye una herramienta para conocer la información disponible y detectar necesidades de mejora en su registro y organización.

En esta etapa no se establecen relaciones causales, no se realizan pruebas estadísticas y no se formulan conclusiones definitivas sobre el desempeño del servicio. Los hallazgos obtenidos sirven como punto de partida para investigaciones posteriores.