Introducción

El seguro de gastos médicos se define como un plan de protección financiera ante los gastos clínicos que pueda erogar alguna enfermedad y/o accidente, a través de un respaldo económico que permite resguardar la salud y bienestar del asegurado.

Tiene por objetivo satisfacer la necesidad económica derivada de la atención médica, gastos hospitalarios y demás que sean necesarios para la recuperación de la salud del individuo, en el momento en que este haya sido afectado a causa de un accidente y/o enfermedad.

Esta publicación expone un análisis sobre los siniestros reportados y pagados del ramo de gastos médicos individuales en México para el año 2023; en primer lugar, se presenta una justificación teórica sobre el enfoque del análisis. Posteriormente se exhibe un Análisis Exploratorio de los Datos (EDA), donde se localizan relaciones, similitudes, patrones e información relevante para su detallada interpretación. Finalmente se ofrece una explicación detallada resultante del EDA junto con la creación del modelo que permita comprender y predecir el comportamiento de los siniestros de este sector.

Objetivo

Clusterizar la información de siniestros en el ramo de gastos médicos individuales, dándole énfasis al monto pagado, para poder comprender mejor porque en los últimos años no se reportan ganancias.

Los clusters tienen el objetivo de identificar cuales son las variables más significativas para cada grupo, de igual forma, localizar específicamente que elementos son los que más se repiten donde los montos pagados son más altos, es decir, identificar un patrón, para así poder pronosticar futuros comportamientos con objeto de ajustar los montos de las primas de los próximos años.

Revisión de Literatura

El impacto del seguro de gastos médicos en México es y ha sido una interrogante poco estudiada desde su origen, esto ha derivado de la poca cultura de la prevención que existe en el país, y en general, de la latente falta de educación financiera. Sin embargo esto se encuentra justificado medianamente en el hecho de que la mayoría de la población lo ve como un gasto no primordial, pues muchos mexicanos priorizan necesidades inmediatascomo la alimentación o la vivienda antes que la cobertura médica. Por ello, no es de sorprenderse que según la CONDUSEF, con base en datos de la INEGI, tan solo el 77% de la población mexicana está protegida por alguna institución de Seguridad Social, mientras que el resto no, y de ese porcentaje tan solo un 7% es el que cuenta con una póliza para cubrir los imprevistos ante alguna enfermedad y/O accidente que requiera atención méica.

En 2006, Illescas escribió sobre la complejidad del seguro de Gastos Médicos, y detalló como esta radica en la determinación adecuada de la prima, pues se trata de seguros que implican riesgos muy altos y por ende costos muy elevados. Un claro ejemplo de lo que la autora describe es como para 2015 las aseguradoras hicieron frente a un aproximado de 900 mil accidentes y enfermedades por un costo por encima de los 35 mil millones de pesos. Si bien, existen por lo menos 32 compañías con la capacidad de operar el ramo de salud, tan solo 9 son las que concentran la mayor parte del mercado, entonces, estas compañías fueron las que asumieron esa responsabilidad.

La AMIS informó que, en los últimos cuatro años, el gasto de las aseguradoras en atención médica ha superado en algunos casos el 100% de los pagos realizados por los clientes.

En 2021, estos gastos representaron el 105% de las primas pagadas por los asegurados; en 2022 se redujeron al 98%, en 2023 aumentaron al 99% y en 2024 volvieron a superar los ingresos, alcanzando el 101%.

Esta situación ha generado pérdidas operativas para las aseguradoras especializadas en salud, con márgenes de ganancia mínimos que no superan el 1% o 2% de los pagos realizados.

El incremento en los costos de atención médica se debe principalmente al encarecimiento de los servicios, tratamientos, materiales y dispositivos médicos, lo que ha puesto en riesgo la rentabilidad del sector asegurador.

Es aquí donde surge nuestra detonante qué ajustes podrían realizarse en las pólizas con base a la siniestralidad, pues sin lugar a dudas los costos médicos seguirán aumentando en el futuro.

Análisis Exploratorio de Datos (EDA)

Carga y limpieza de los datos

# Cargar los datos
base <- read_excel("gmi.xlsx")

# Revisar y limpiar los datos

# Verificar si existen vacíos
sum(is.na(base))

# Buscar y eliminar duplicados
base |> 
  janitor::get_dupes()
## No variable names specified - using all columns.
base <- base |> 
  distinct()

Descripción de las variables

# Verificar la estructura de las variables
str(base)

# Cambiar formato de variables que no pueden trabajarse bajo su estructura original
cols <- c("SEXO", "ENTIDAD", "TIPO_DE_SEGURO", "TIPO_DE_PAGO", "CATEGORÍA_SINIESTRO", "CAUSA_DEL_SINIESTRO")
base[cols] <- lapply(base[cols], factor)
# Comprobar el cambio
str(base)
## tibble [133,031 × 14] (S3: tbl_df/tbl/data.frame)
##  $ EDAD                   : num [1:133031] 0 0 0 0 0 0 0 0 0 0 ...
##  $ TIPO_DE_SEGURO         : Factor w/ 4 levels "GM Indemnizatorios",..: 2 2 3 1 2 2 2 2 2 2 ...
##  $ ENTIDAD                : Factor w/ 34 levels "Aguascalientes",..: 8 28 24 26 16 16 16 16 7 33 ...
##  $ SEXO                   : Factor w/ 2 levels "Femenino","Masculino": 2 2 2 1 1 1 1 2 2 1 ...
##  $ TIPO_DE_PAGO           : Factor w/ 12 levels "Ambulancia","Aparatos ortopédicos",..: 9 9 6 9 9 9 9 9 9 9 ...
##  $ CAUSA_DEL_SINIESTRO    : Factor w/ 5407 levels "(OSTEO)ARTROSIS EROSIVA",..: 984 697 4270 697 4010 727 697 4152 3967 4152 ...
##  $ CATEGORÍA_SINIESTRO    : Factor w/ 20 levels "Afecciones al Sistema Inmunológico",..: 11 14 11 14 19 19 14 9 8 9 ...
##  $ NUMERO_DE_SINIESTROS   : num [1:133031] 1 1 1 1 1 1 1 1 1 1 ...
##  $ NUMERO_DE_RECLAMACIONES: num [1:133031] 1 1 1 1 1 1 1 1 1 1 ...
##  $ MONTO_RECLAMADO        : num [1:133031] 10 16.7 16.7 17.6 24.8 ...
##  $ MONTO_DE_DEDUCIBLE     : num [1:133031] 0 0 0 0 0 0 0 0 0 0 ...
##  $ MONTO_DE_COASEGURO     : num [1:133031] 0 0 4.18 4.4 0 0 0 0 0 0 ...
##  $ MONTO_PAGADO           : num [1:133031] 10 16.7 16.7 17.6 24.8 ...
##  $ MONTO_DE_REASEGURO     : num [1:133031] 0 0 0 8.8 0 0 0 0 0 0 ...

El conjunto de datos consta de 14 variables, de las cuales 6 son categóricas y 8 numéricas.

Variables categóricas:

  1. Tipo de seguro. Cuenta con cuatro niveles: ‘GM Indemnizatorios’, ‘GM Plan Limitado’, ‘GM PLan Amplio’ y ‘GM Plan Internacional’.
  2. Entidad. Sus niveles comprenden las 32 entidades federativas que conforman la República Mexicana, así como el nivel denominado ‘extranjero’ y ‘desconocido o sin domicilio fijo’.
  3. Sexo. Puede tomar los valores categóricos ‘femenino’ o ‘masculino’.
  4. Tipo de pago. Explica la causa por la cual se realiza el pago, estas incluyen: Ambulancia, aparatos ortopédicos, estudios de gabinete, estudios de laboratorio, gasto indemnizatorio, honorarios, honorarios de enfermeras, hospitalización, medicamentos, otros, prótesis y ortesis, y rehabiltación.
  5. Causa del siniestro, Identifica por lo menos 5000 causas diferentes.
  6. Categoría del siniestro. Es una variable elaborada a partir de la variable anterior con objeto de clasificar de forma más eficiente las causas de los siniestros en grupos más específicos y manejables. Entre sus 20 niveles se encuentran diferentes afecciones de sistemas tales como el inmunológico, respiratorio, digestivo, entre otros; exámenes y consultas, malformaciones congénitas, trastornos mentales y del comportamiento, factores externos, diferentes enfermedades, neoplasias, lesiones y otras causas.

Variables numéricas:

  1. Edad. Comprende valores del 0 al 102.
  2. Número de siniestros. Con valores de 1 a 74.
  3. Número de reclamaciones. Cuyos valores abarcan de 1 a 97.
  4. Monto reclamado. Se trata de la cantidad que el asegurado reclama por los siniestros que ha sufrido. Con un mínimo de -964,693.6 y un máximo de 30,612,841.
  5. Monto de deducible. Refiere a la cantidad que el asegurado debe pagar por los daños o costos de reposición. Con un mínimo de 0 y un máximo de 644,074.2
  6. Monto de coaseguro. Es el porcentaje del costo total que el asegurado debe pagar después de que se haya cubierto el deducible. Su rango de valores integra un mínimo de 0 y un maximo de 934,873.1
  7. Monto pagado. Refiere al monto total que la aseguradora paga por los gastos médicos después de haber aplicado los deducibles y el coaseguro. Con un mínimo de 0.5 y un máximo de 30,612,841.
  8. Monto de reaseguro. Es la cantidad que la aseguradora ha transferido a otra entidad para cubrir parte del riesgo. Con un mínimo de -109,112.5 y un máximo de 264,984.5

Estadísticas descriptivas

Nuestra variable de interés a analizar es el monto pagado, pues resulta ser el efectivo ante el monto reclamado, lo cual permite conocer cuanto están pagando realmente las aseguradoras por los gastos médicos de los asegurados siniestrados.

  • Media: 13,223
  • Mediana 2,700
  • Moda: 700
  • Desviación estándar: 158,617.9
  • Monto mínimo: 0
  • Monto máximo: 30,612,841
  • Cuantil Q1: 1,034
  • Cuantil Q3: 7,200
  • Coeficiente de variación: 1199.58
  • Asimetría: 95.26
  • Curtosis: 14043.51

Visualización de datos

Análisis de Correlación

base_n <- base |>
  select(where(is.numeric))
colnames(base_n) <- c("Edad", "No.Siniestros", "No.Reclamaciones", 
                      "Mon.Reclamado", "Mon.Deducible", "Mon.Coaseg", 
                      "Mon.Pagado", "Mon.Reaseguro")
cor_matrix <- cor(base_n)
corrplot::corrplot(cor(base_n),method = 'shade', col = COL2("BrBG"),  
                   addCoef.col = 'gray28', number.cex = 0.7,
                   tl.col = "black", tl.cex = 0.9)

# Puede eliminarse la var MONTO DE RECLAMACIÓN y varias más

aov_mp_ed <- aov(MONTO_PAGADO ~ EDAD, data=base)
summary(aov_mp_ed)
##                 Df    Sum Sq   Mean Sq F value Pr(>F)    
## EDAD             1 1.536e+13 1.536e+13   613.2 <2e-16 ***
## Residuals   133029 3.332e+15 2.504e+10                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
aov_mp_ns <- aov(MONTO_PAGADO ~ NUMERO_DE_SINIESTROS, data=base)
summary(aov_mp_ns)
##                          Df    Sum Sq   Mean Sq F value Pr(>F)    
## NUMERO_DE_SINIESTROS      1 8.653e+13 8.653e+13    3531 <2e-16 ***
## Residuals            133029 3.260e+15 2.451e+10                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
aov_mp_nr <- aov(MONTO_PAGADO ~ NUMERO_DE_RECLAMACIONES, data=base)
summary(aov_mp_nr)
##                             Df    Sum Sq   Mean Sq F value Pr(>F)    
## NUMERO_DE_RECLAMACIONES      1 7.023e+13 7.023e+13    2851 <2e-16 ***
## Residuals               133029 3.277e+15 2.463e+10                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
aov_mp_de <- aov(MONTO_PAGADO~MONTO_DE_DEDUCIBLE, data= base)
summary(aov_mp_de)
##                        Df    Sum Sq   Mean Sq F value Pr(>F)    
## MONTO_DE_DEDUCIBLE      1 4.316e+14 4.316e+14   19694 <2e-16 ***
## Residuals          133029 2.915e+15 2.192e+10                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
aov_mp_ent <- aov(MONTO_PAGADO~ENTIDAD, data = base)
summary(aov_mp_ent)
##                 Df    Sum Sq   Mean Sq F value  Pr(>F)   
## ENTIDAD         33 1.481e+12 4.488e+10   1.784 0.00369 **
## Residuals   132997 3.346e+15 2.515e+10                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
aov_mp_ts <- aov(MONTO_PAGADO~TIPO_DE_SEGURO, data= base)
summary(aov_mp_ts)
##                    Df    Sum Sq   Mean Sq F value   Pr(>F)    
## TIPO_DE_SEGURO      3 1.077e+12 3.589e+11   14.27 2.71e-09 ***
## Residuals      133027 3.346e+15 2.515e+10                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
aov_mp_tp <- aov(MONTO_PAGADO~TIPO_DE_PAGO, data= base)
summary(aov_mp_tp)
##                  Df    Sum Sq   Mean Sq F value Pr(>F)    
## TIPO_DE_PAGO     11 1.405e+13 1.277e+12   50.96 <2e-16 ***
## Residuals    133019 3.333e+15 2.506e+10                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
aov_mp_sx <- aov(MONTO_PAGADO~SEXO, data= base)
summary(aov_mp_sx)
##                 Df    Sum Sq   Mean Sq F value   Pr(>F)    
## SEXO             1 3.483e+11 3.483e+11   13.84 0.000199 ***
## Residuals   133029 3.347e+15 2.516e+10                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
aov_mp_co <- aov(MONTO_PAGADO~MONTO_DE_COASEGURO, data= base)
summary(aov_mp_co)
##                        Df    Sum Sq   Mean Sq F value Pr(>F)    
## MONTO_DE_COASEGURO      1 9.963e+14 9.963e+14   56382 <2e-16 ***
## Residuals          133029 2.351e+15 1.767e+10                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
aov_mp_re <- aov(MONTO_PAGADO~MONTO_DE_REASEGURO, data= base)
summary(aov_mp_re)
##                        Df    Sum Sq   Mean Sq F value   Pr(>F)    
## MONTO_DE_REASEGURO      1 1.637e+12 1.637e+12   65.08 7.26e-16 ***
## Residuals          133029 3.345e+15 2.515e+10                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Identificación de datos atípicos

## De forma tradicional con cuantiles

# Monto Pagado
umbral_mp <- quantile(base$MONTO_PAGADO, 0.95, na.rm = T)
atipicos_mp <-base$MONTO_PAGADO[base$MONTO_PAGADO>umbral_mp]
normales_mp <- base$MONTO_PAGADO[base$MONTO_PAGADO<=umbral_mp]

nor_mp <- as.data.frame(normales_mp)
ggplot(nor_mp, aes(normales_mp))+
  geom_density(color = "paleturquoise4", linewidth = 1.2)+ 
  theme_minimal() +
  theme(plot.title = element_text(family = "serif", size = 17, 
                                  hjust = 0.5, vjust = 1, 
                                  color = "#00838f"), 
        plot.title.position = "plot",
        axis.title.x = element_text(family = "serif"),
        axis.title.y = element_text(family = "serif"),
        axis.text.x = element_text(size = 7, angle = 45, hjust = 1),
        axis.text.y = element_text(size = 7),
        axis.line = element_line(color = "gray75")) +
  labs(title = 'DATOS ATÍPICOS DEL MONTO PAGADO POR CUANTILES', 
       y = 'Densidad', x = "Monto Pagado")

# Estos datos podrían seguir alguna distribución, por lo que valdría la pena revisar

#Edad
umbral_ed <- quantile(base$EDAD, 0.95, na.rm = T)
atipicos_ed <-base$EDAD[base$EDAD>umbral_ed]
normales_ed <- base$EDAD[base$EDAD<=umbral_ed]

nor_ed <- as.data.frame(normales_ed)

ggplot(nor_ed, aes(normales_ed)) +
  geom_density(color = "paleturquoise4", linewidth = 1.2) + 
  theme_minimal() +
  theme(plot.title = element_text(family = "serif", size = 17, 
                                  hjust = 0.5, vjust = 1, 
                                  color = "#00838f"), 
        plot.title.position = "plot",
        axis.title.x = element_text(family = "serif"),
        axis.title.y = element_text(family = "serif"),
        axis.text.x = element_text(size = 7, angle = 45, hjust = 1),
        axis.text.y = element_text(size = 7),
        axis.line = element_line(color = "gray75")) +
  labs(title = 'DATOS ATÍPICOS DE LA EDAD POR CUANTILES', 
       y = 'Densidad', x = "Edad")

# Los valores atipicos de edad no son tan relevantes
## Con la distancia de Mahalanobis

dist_mah <- mahalanobis(base_n, colMeans(base_n), cov(base_n))
out <- c(rep(NA, nrow(base_n)))
umbral_mah <- qchisq(0.95, df = ncol(base_n)) 
out<- ifelse(dist_mah>umbral_mah,'Si','No')
sum(out=='Si')
## [1] 5204
base_nat <- data.frame(base_n, out)
base_nat <- base_nat |>
  filter(out=='No')
# Vemos que con la distancia de Mahalanobis son 5204 datos, menos que si solo nos enfocamos en los atipicos de MONTO_PAGADO

ggplot(base_nat, aes(Mon.Pagado)) +
  geom_density(color = "paleturquoise4", linewidth = 1.2)+ 
  theme_minimal() +
  theme(plot.title = element_text(family = "serif", size = 17, 
                                  hjust = 0.5, vjust = 1, 
                                  color = "#00838f"), 
        plot.title.position = "plot",
        axis.title.x = element_text(family = "serif"),
        axis.title.y = element_text(family = "serif"),
        axis.text.x = element_text(size = 7, angle = 45, hjust = 1),
        axis.text.y = element_text(size = 7),
        axis.line = element_line(color = "gray75")) +
  labs(title = 'DATOS ATÍPICOS DEL MONTO PAGADO POR\nDISTANCIA DE MAHALONOBIS', 
       y = 'Densidad', x = "Monto Pagado")

Aplicación de técnicas multivariantes para reducir dimensiones

Es posible reducir dimensiones, y, tomando en cuenta que se realizará un análisis de clusters como modelo, la forma correcta de reducir dimensiones sería con un análisis de componentes principales (PCA), sin embargo, también podría ser de utilidad algo un poco más especializado, como lo es un análisis factorial para datos mixtos (FAMD).

Métodología

Primeramente, se realizó un análisis de literatura para identificar los datos de interés. Una vez decidido el tema se inició la búsqueda de una base de datos adecuada, misma que se obtuvo de la página de la CNSF, en específico, el conjunto de datos del año 2023 para Gastos Médicos Individuales.

La base de datos se importó a R (lenguaje de programación), para posteriormente proceder a limpiar dicha base, cabe destacar que el proceso de vio facilitado gracias a que no había presencia de datos vacíos. Por consiguiente, se eliminaron los datos duplicados, y como parte final de la limpieza se analizó la estructura de los datos, donde se logró identificar que algunas de las variables no contaban con la estructura adecuada por lo que se corrigieron para seguir adelante en el trabajo.

Con la base de datos limpia lo primero que se realizó fue la obtención de estadísticas descriptivas, incluyendo datos como la media, la moda, el máximo, entre otros; todo ello con respecto a la variable de interés principal ‘Monto Pagado’, de igual forma, se realizaron consultas en las que se promediaron o acumularon valores, para posteriormente realizar gráficos que permitiesen una interpretación más sencilla de los datos.

También se buscaron valores atípicos, esto fue realizado de dos formas. La primera fue de manera empírica, en la cual se calculó el cuantil 95 de los datos correspondientes al monto pagado, el resultado arrojó que aproximadamente un poco más 6000 datos se encuentran fuera de este cuantil. El segundo método fue el de la distancia de Mahalanobis, la cual mostró que hay aproximadamente poco más 5000 datos atípicos. Por lo que se llegó a la conclusión de que en la base de datos se encuentran entre 5000 y 6000 datos atípicos.

Finalmente, con ayuda de la investigación previa se estableció que lo ideal sería utilizar un modelo clúster, pero para poder aplicarlo, primero se busca disminuir la cantidad de variables para facilitar el cálculo, esto se hará mediante un FAMD (Análisis Factorial de Datos Mixtos); esta técnica es utilizada para datos con variables de diferentes tipos, como pueden ser categóricas y numéricas. El FAMD identifica los componentes principales que explican la mayor varianza entre los datos, dentro del análisis se hace un tratamiento a las variables, si son cuantitativas las estandariza y a las cualitativas las convierte en variables dummy.

Propuesta de Modelo

Descripción del modelo propuesto

El modelo propuesto es un análisis de clúster, donde se crearán grupos o conglomerados de la base datos que se está trabajando.

El objetivo del análisis de clúster es organizar datos sin etiquetas en grupos de manera que los elementos dentro de un mismo clúster sean más parecidos entre sí que con los elementos de otros clústeres. Esto se logra mediante algoritmos que miden la similitud entre los datos según ciertos criterios, como la distancia euclidiana o la similitud de coseno.

Aunque existen diferentes tipos de algoritmos para realizar este modelo, pero en este caso se tienen dos propuestas:

  • K-Prototypes, que es una extensión del algoritmo de K-means(descripción de este), que combina la distancia euclidiana y la distancia de Haming.

  • Clustering jerárquico empleando la distancia de Gower para medir la similitud entre las variables y posteriormente aplicar un método jerárquico como Ward para formar los clústeres.

Justificación de la elección del modelo

Tener clusterizados los datos, facilitará el análisis de los datos con mayor siniestralidad pagada, para así poder descubrir cuales son las características que tienen en común estos siniestros, poder restringirlos y generar propuestas para la modificación de las primas solo a diversos clientes que cumplan con las características más significativas que se hayan observado en el clúster de interés.

Se usa el modelo, porque es la forma más practica de segmentarlo por distancias analizando los datos entre sí, que simplemente proponer grupos. Además de que dicho modelo tiene múltiples formas de hacerlo, dependiendo la cantidad de datos, estructura y tipo; por lo que facilita el trabajo usando el algoritmo correcto.

Referencias

  • Illescas, A. (2006). SEGURO DE GASTOS MÉDICOS MAYORES Y SU ACTUALIDAD EN MÉXICO. [Tesis de licenciatura, Universidad Nacional Autónoma de México]. UNAM - Dirección General de Bibliotecas.

  • Zárate, T. (2017). Modelo para evaluar la competitividad de productos de seguros de gastos médicos mayores individual en una aseguradora del mercado nacional. [Tesina, Universidad Autónoma del Estado de México].

  • Asociación Mexicana de Instituciones de Seguros. (s.f.). Seguro de Gastos Médicos – Seguros de Salud. https://amissegurosdesalud.com.mx/seguro-gastos-medicos/

  • Comisión Nacional para la Protección y Defensa de los Usuarios de Servicios Financieros. (s.f.). Presenta CONDUSEF Simulador de Gastos Médicos Mayores. https://www.condusef.gob.mx/?p=contenido&idc=544&idcat=1#:~:text=En%20M%C3%A9xico%20existen%2032%20compa%C3%B1%C3%ADas,resolvieron%20a%20favor%20del%20usuario