Análisis Extendido de Tarificación Telemática: Un Enfoque Dual con Índices de Comportamiento
Author
AC (Versión Mejorada)
Published
June 16, 2025
1. Introducción al Análisis de Tarificación Telemática
1.1. ¿Qué es la Tarificación Telemática?
La tarificación telemática, también conocida como “pago por uso” (Pay-As-You-Drive) o “pago por cómo se conduce” (Pay-How-You-Drive), es un paradigma innovador en el sector de los seguros de automóviles. En lugar de basar las primas únicamente en factores demográficos y de historial tradicionales (edad, sexo, lugar de residencia, historial de siniestros), la telemática incorpora datos en tiempo real sobre el comportamiento de conducción.
Mediante dispositivos instalados en el vehículo o aplicaciones móviles, se recopila información detallada como la velocidad, los patrones de aceleración y frenado, los giros, las distancias recorridas y los horarios de conducción. Estos datos permiten a las aseguradoras crear un perfil de riesgo mucho más preciso y personalizado para cada conductor, recompensando los hábitos de conducción seguros con primas más bajas y, a la inversa, ajustando las tarifas para los conductores de mayor riesgo.
1.2. El Dataset: catelematic13 de CASdatasets
Para este análisis, utilizaremos el conjunto de datos catelematic13, disponible en el paquete de R CASdatasets. Este dataset proviene de una aseguradora canadiense y contiene información de una cartera de pólizas de automóviles donde se ha implementado un programa telemático. Es un recurso excelente para explorar cómo los datos de comportamiento pueden complementar los factores de tarificación tradicionales.
Variables Clave en el Dataset
El conjunto de datos se compone de tres grandes grupos de variables:
Variables Demográficas del Asegurado:
InsuredAge, InsuredSex, Marital: Edad, sexo y estado civil del conductor.
Variables del Vehículo:
CarAge, CarUse, Region: Antigüedad, uso principal (privado o comercial) y región de circulación del vehículo.
Variables Telemáticas y de Exposición:
TotalMilesDriven: Millas totales conducidas durante el período de observación.
Variables PctDrive...: Porcentaje del tiempo de conducción distribuido por día de la semana, hora del día (ej. PctDriveRushAM para hora punta matutina) y franjas horarias.
Variables Accel..., Brake..., LeftTurn..., RightTurn...: Conteos de eventos de aceleración, frenado y giros, categorizados por su intensidad (ej. Accel.0.2.0.4 se refiere a eventos de aceleración de intensidad media-baja).
Variable Objetivo:
NbClaim, AmtClaim: Número de siniestros y monto total de los mismos, que son las variables que buscamos predecir.
1.3. Enfoque de Modelado: Tradicional vs. Índices de Comportamiento
Este informe implementará y comparará dos metodologías de modelado para evaluar el impacto de las variables telemáticas:
Ruta A - Enfoque Tradicional con Selección de Variables:
Se realiza una ingeniería de características básica (ej. frenos_por_milla).
Se utiliza una técnica de regularización, Elastic Net, para seleccionar automáticamente el subconjunto de variables (demográficas y telemáticas) más predictivo de entre un gran número de candidatos.
Este enfoque es potente pero puede carecer de interpretabilidad, ya que la selección es puramente algorítmica.
Ruta B - Enfoque Sofisticado con Índices de Comportamiento:
Se agrupan las variables telemáticas en “dimensiones” lógicas de riesgo (ej. Agresividad, Patrón de Uso).
Se construyen índices para cada dimensión. Cada índice es en sí mismo un pequeño modelo que resume el riesgo de esa faceta del comportamiento en un solo número.
Este enfoque es más interpretable, ya que permite al analista entender qué tipos de comportamiento son más relevantes para el riesgo, en lugar de solo identificar variables individuales.
Ventajas del Enfoque con Índices
El enfoque de índices (Ruta B) ofrece varias ventajas clave, especialmente en el contexto actuarial: * Interpretabilidad Mejorada: Es más fácil explicar al negocio o a un regulador que el “índice de agresividad” de un conductor es alto, que explicar el impacto de diez variables individuales de aceleración y frenado. * Robustez: Al promediar la señal de múltiples variables, los índices tienden a ser más estables y menos sensibles al ruido que las variables individuales. * Reducción de Dimensionalidad Inteligente: Simplifica el modelo final de una manera guiada por el conocimiento del negocio, no solo por optimización matemática.
A lo largo de este documento, desarrollaremos ambas rutas y compararemos sus resultados para determinar qué enfoque ofrece el mejor equilibrio entre poder predictivo y valor de negocio.
2. Carga y Preparación de Datos
El proceso comienza con la carga del dataset, seguido de una limpieza estándar para asegurar la calidad de los datos y la creación de variables objetivo fundamentales.
# Carga de datosdata("catelematic13", package ="CASdatasets")# Limpieza y preparación inicialdatos_base <- catelematic13 %>% janitor::clean_names() %>%# TRADUCCIÓN: Renombrar solo las columnas principales a español para mayor claridad y robustez. dplyr::rename(n_siniestros = nb_claim,monto_siniestro = amt_claim,millas_totales_conducidas = total_miles_driven,edad_asegurado = insured_age,sexo_asegurado = insured_sex,estado_civil = marital,antiguedad_vehiculo = car_age,uso_vehiculo = car_use,region = region ) %>%filter(millas_totales_conducidas >0, antiguedad_vehiculo >=0, monto_siniestro >=0) %>%mutate(across(where(is.character), as.factor),tasa_frecuencia = n_siniestros / millas_totales_conducidas,indicador_siniestro =ifelse(n_siniestros >0, 1, 0) )# Vista previa de los datoshead(datos_base)
Antes de modelar, es crucial entender la distribución de las variables y su relación con la siniestralidad.
3.1. Variables Demográficas y del Vehículo
Gráficos de Densidad para Variables Continuas
# Densidad de la Edad del Aseguradop1 <-ggplot(datos_base, aes(x = edad_asegurado)) +geom_density(fill ="#0275D8", alpha =0.7) +labs(title ="Distribución de la Edad del Asegurado", x ="Edad", y ="Densidad") +theme_light()# Densidad de la Antigüedad del Vehículop2 <-ggplot(datos_base, aes(x = antiguedad_vehiculo)) +geom_density(fill ="#5CB85C", alpha =0.7) +labs(title ="Distribución de la Antigüedad del Vehículo", x ="Antigüedad (Años)", y ="Densidad") +theme_light()# Combinar gráficosp1 + p2
Gráficos de Barras para Variables Categóricas
# Función auxiliar para gráficos de frecuencia mediaplot_freq_media <-function(data, var) { data %>%group_by({{var}}) %>%summarise(freq_media =mean(tasa_frecuencia) *1000, n =n()) %>%filter(n >30) %>%ggplot(aes(x =reorder({{var}}, -freq_media), y = freq_media)) +geom_col(fill ="#D9534F") +labs(y ="Frecuencia Media (/1000 millas)", x ="") +theme_light() +theme(axis.text.x =element_text(angle =45, hjust =1))}# Frecuencia por Región y Uso del Vehículop_region <-plot_freq_media(datos_base, region) +labs(title ="Frecuencia por Región")p_uso <-plot_freq_media(datos_base, uso_vehiculo) +labs(title ="Frecuencia por Uso del Vehículo")p_region + p_uso
4. Ingeniería de Características
Se preparan las variables telemáticas para el modelado. Este es el punto donde nuestras dos rutas de análisis divergen.
En esta ruta, utilizaremos un conjunto amplio de características y dejaremos que un algoritmo de regularización, Elastic Net, seleccione las más importantes.
4.1.A. Selección de Variables con Elastic Net
Concepto: Elastic Net es un modelo de regresión que penaliza la complejidad del modelo, forzando a que los coeficientes de las variables menos importantes se reduzcan a cero. Es una mezcla de las penalizaciones Lasso (que es buena para la selección de variables) y Ridge (que es buena para manejar predictores correlacionados). El resultado es un modelo más simple y robusto.
# Preparar datos para Elastic Netvars_predictoras_A <- datos_ingenieria %>% dplyr::select(# Demográficas edad_asegurado, sexo_asegurado, antiguedad_vehiculo, estado_civil, region, uso_vehiculo,# Telemáticas de Ingeniería aceleraciones_totales, frenadas_totales, giros_totales, pct_manejo_punta_total, frenadas_por_milla, aceleraciones_por_milla, giros_por_milla,# Telemáticas originales de % de uso (nombres originales)starts_with("pct_drive_") )matriz_x_A <-model.matrix(~ . -1, data = vars_predictoras_A)vector_y_A <- datos_ingenieria$n_siniestrosoffset_A <-log(datos_ingenieria$millas_totales_conducidas)# Ajustar Elastic Net con validación cruzadaset.seed(123)ajuste_enet <-cv.glmnet(matriz_x_A, vector_y_A, family ="poisson", offset = offset_A, alpha =0.5)# Extraer las variables seleccionadas (coeficientes no nulos)coeficientes_enet <-coef(ajuste_enet, s ="lambda.1se")vars_seleccionadas_enet <-rownames(coeficientes_enet)[coeficientes_enet[, 1] !=0]# Excluir el interceptovars_seleccionadas_enet <- vars_seleccionadas_enet[vars_seleccionadas_enet !="(Intercept)"]cat("--- Variables Seleccionadas por Elastic Net ---\n")
Ahora, ajustamos los modelos finales usando solo el conjunto de predictores que Elastic Net consideró relevantes.
Modelos Utilizados
GLM (Modelo Lineal Generalizado): Es la extensión de la regresión lineal para variables de respuesta que no siguen una distribución normal (como nuestro conteo de siniestros). Usamos una familia Poisson, adecuada para datos de conteo. Es simple, rápido y muy interpretable.
Random Forest: Es un modelo de ensamblaje que construye múltiples árboles de decisión y promedia sus predicciones. Es muy potente, captura interacciones complejas y es robusto al sobreajuste. Su desventaja es que es una “caja negra”, menos interpretable que un GLM.
# Las predicciones del modelo GLM se harán directamente desde el objeto 'ajuste_enet'.# Fórmula para Random Forest# Es necesario recrear un dataframe con las variables seleccionadas por enet# ya que RF no puede usar la matriz directamente de la misma forma.datos_para_rf_enet <-as.data.frame(as.matrix(matriz_x_A[, vars_seleccionadas_enet]))datos_para_rf_enet$tasa_frecuencia <- datos_ingenieria$tasa_frecuenciaformula_rf_enet <-as.formula(paste("tasa_frecuencia ~ ."))modelo_rf_enet <- randomForest::randomForest(formula_rf_enet, data = datos_para_rf_enet, ntree =50)
RUTA B: ENFOQUE SOFISTICADO CON ÍNDICES
En esta ruta, creamos nuestros propios predictores de alto nivel (índices) basados en el conocimiento del negocio.
4.1.B. Creación de Índices de Comportamiento
Concepto: En lugar de tratar cada variable telemática por separado, las agrupamos en dimensiones lógicas (Agresividad, Patrón de Uso, etc.). Para cada dimensión, ajustamos un mini-modelo GLM para predecir la siniestralidad. La predicción de este modelo, estandarizada, se convierte en nuestro “índice”, un único y potente predictor que resume esa faceta del comportamiento.
# Función Auxiliar para Crear Índicescrear_indice <-function(data, vars_dimension) {if (length(vars_dimension) ==0) return(rep(0, nrow(data))) formula_dim <-as.formula(paste("n_siniestros ~", paste(vars_dimension, collapse =" + "), "+ offset(log(millas_totales_conducidas))")) modelo_dim <-glm(formula_dim, data = data, family =poisson(link ="log")) indice_bruto <-predict(modelo_dim, type ="response") / data$millas_totales_conducidasif (sd(indice_bruto, na.rm =TRUE) >1e-6) return(as.numeric(scale(indice_bruto)))elsereturn(rep(0, length(indice_bruto)))}# Definir Dimensiones y Crear los Índicesvars_agresividad <-c("frenadas_por_milla", "aceleraciones_por_milla")vars_curvas <-c("giros_por_milla")vars_patron_horario <-c("pct_manejo_punta_total")# Se usan los nombres originales de las columnas, que empiezan con 'pct_drive_'vars_patron_semanal <-names(datos_ingenieria)[grepl("^pct_drive_(mon|tue|th|fri|sat|sun)$", names(datos_ingenieria))]datos_con_indices <- datos_ingenieria %>%mutate(indice_agresividad =crear_indice(., vars_agresividad),indice_curvas =crear_indice(., vars_curvas),indice_patron_horario =crear_indice(., vars_patron_horario),indice_patron_semanal =crear_indice(., vars_patron_semanal) )summary(dplyr::select(datos_con_indices, starts_with("indice_")))
indice_agresividad indice_curvas indice_patron_horario
Min. : -0.072756 Min. : -0.003209 Min. :0
1st Qu.: -0.004595 1st Qu.: -0.003209 1st Qu.:0
Median : -0.004593 Median : -0.003208 Median :0
Mean : 0.000000 Mean : 0.000000 Mean :0
3rd Qu.: -0.004586 3rd Qu.: -0.003207 3rd Qu.:0
Max. :243.005484 Max. :313.138896 Max. :0
indice_patron_semanal
Min. :-5.14529
1st Qu.:-0.49198
Median :-0.05787
Mean : 0.00000
3rd Qu.: 0.42245
Max. :23.83461
4.2.B. Análisis Descriptivo de los Índices
Verificamos que nuestros índices no estén demasiado correlacionados, lo que confirmaría que miden aspectos distintos del riesgo. El índice_patron_horario muestra una varianza nula, lo que significa que la variable pct_manejo_punta_total no tiene poder predictivo por sí sola en este contexto y será excluida de los modelos.
# Filtrar índices con varianza cero antes de graficarindices_para_analisis <- datos_con_indices %>% dplyr::select(starts_with("indice_")) %>% dplyr::select(where(~sd(.x, na.rm =TRUE) >1e-6))# Gráfico de Cajas (Box Plot) para visualizar la distribuciónif (ncol(indices_para_analisis) >0) { plot_cajas <- indices_para_analisis %>% tidyr::pivot_longer(everything(), names_to ="indice", values_to ="valor") %>%ggplot(aes(x = indice, y = valor, fill = indice)) +geom_boxplot() +labs(title ="Distribución de los Índices de Comportamiento", x ="Índice", y ="Valor Estandarizado") +theme_light() +theme(legend.position ="none", axis.text.x =element_text(angle =45, hjust =1))print(plot_cajas)} else {cat("No hay índices con varianza para graficar su distribución.\n")}
4.3.B. Modelado con Índices
Ajustamos los mismos tipos de modelos (GLM y Random Forest), pero esta vez usando nuestros índices de alto nivel como predictores.
# Preparar Fórmulasvariables_demograficas <-c("edad_asegurado", "sexo_asegurado", "antiguedad_vehiculo", "estado_civil", "region", "uso_vehiculo")variables_indices <-names(indices_para_analisis)predictores_indices <-c(variables_demograficas, variables_indices)formula_indices_texto <-paste(predictores_indices, collapse =" + ")formula_base_texto <-paste(variables_demograficas, collapse =" + ")# Modelo 1: GLM Base (común a ambas rutas, solo demografía)modelo_glm_base <-glm(as.formula(paste("n_siniestros ~", formula_base_texto, "+ offset(log(millas_totales_conducidas))")), data = datos_con_indices, family =poisson(link ="log"))# Modelo 2B: GLM con Índicesmodelo_glm_indices <-glm(as.formula(paste("n_siniestros ~", formula_indices_texto, "+ offset(log(millas_totales_conducidas))")), data = datos_con_indices, family =poisson(link ="log"))# Modelo 3B: Random Forest con Índicesformula_rf_indices <-as.formula(paste("tasa_frecuencia ~", formula_indices_texto))modelo_rf_indices <- randomForest::randomForest(formula_rf_indices, data = datos_con_indices, ntree =50)
5. Evaluación de Resultados y Comparación de Rutas
Ahora comparamos el rendimiento de todos los modelos de ambas rutas.
5.1. Criterios de Decisión y su Interpretación
Tabla de Impacto Financiero: Comparamos el “Costo Observado” (la prima pura real) con el costo predicho por cada modelo, agrupando a los asegurados por nivel de riesgo. Un buen modelo tendrá predicciones cercanas a los valores observados en cada grupo.
Lift Chart (Curva de Ganancia): Esta gráfica muestra la capacidad de un modelo para separar a los clientes de alto riesgo de los de bajo riesgo. Una curva que sube rápidamente y se aleja de la diagonal indica un modelo con un alto poder predictivo. Por ejemplo, si la curva muestra que el 20% de la cartera de mayor riesgo (según el modelo) concentra el 50% de los siniestros, el modelo es muy eficiente.
# --- Generación de Predicciones ---datos_resultados <- datos_con_indices %>%mutate(prediccion_glm_base =predict(modelo_glm_base, type ="response"),# Ruta Aprediccion_glm_enet =as.numeric(predict(ajuste_enet, newx = matriz_x_A, s ="lambda.1se", type ="response", newoffset = offset_A)),prediccion_rf_enet =predict(modelo_rf_enet, newdata = datos_para_rf_enet) * millas_totales_conducidas,# Ruta Bprediccion_glm_indices =predict(modelo_glm_indices, type ="response"),prediccion_rf_indices =predict(modelo_rf_indices, type ="response") * millas_totales_conducidas,siniestros_reales = n_siniestros )# --- Impacto Financiero por Grupo de Riesgo ---severidad_promedio <-sum(datos_resultados$monto_siniestro) /sum(datos_resultados$siniestros_reales, na.rm =TRUE)datos_resultados <- datos_resultados %>%mutate(grupo_riesgo =ntile(prediccion_glm_indices, 5)) # Usamos el modelo de índices como referenciaresumen_impacto <- datos_resultados %>%group_by(grupo_riesgo) %>%summarise(Costo_Observado =sum(monto_siniestro) /n(),Costo_Pred_GLM_Base =mean(prediccion_glm_base * severidad_promedio, na.rm=T),Costo_Pred_GLM_ENet =mean(prediccion_glm_enet * severidad_promedio, na.rm=T),Costo_Pred_RF_ENet =mean(prediccion_rf_enet * severidad_promedio, na.rm=T),Costo_Pred_GLM_Indices =mean(prediccion_glm_indices * severidad_promedio, na.rm=T),Costo_Pred_RF_Indices =mean(prediccion_rf_indices * severidad_promedio, na.rm=T),.groups ='drop' ) %>% janitor::adorn_totals("row")cat("\n--- Comparación de Impacto Financiero por Quintil de Riesgo ---\n")
--- Comparación de Impacto Financiero por Quintil de Riesgo ---
knitr::kable(resumen_impacto, digits =2,caption ="Costo Promedio (Prima Pura) por Quintil de Riesgo")
Costo Promedio (Prima Pura) por Quintil de Riesgo
grupo_riesgo
Costo_Observado
Costo_Pred_GLM_Base
Costo_Pred_GLM_ENet
Costo_Pred_RF_ENet
Costo_Pred_GLM_Indices
Costo_Pred_RF_Indices
1
25.84
15.30
19.31
17.35
15.02
19.12
2
49.14
48.30
54.55
50.98
47.56
53.47
3
94.96
91.95
98.34
90.84
90.82
95.94
4
151.95
161.38
165.10
160.07
160.41
158.53
5
344.56
349.52
329.15
349.93
352.65
344.13
Total
666.45
666.45
666.45
669.17
666.45
671.20
# --- NUEVA TABLA: Siniestralidad por Grupo de Riesgo ---resumen_siniestralidad <- datos_resultados %>%group_by(grupo_riesgo) %>%summarise(N_Polizas =n(),N_Siniestros =sum(siniestros_reales),Frecuencia_Observada_x_1000 = (N_Siniestros / N_Polizas) *1000 ) %>% janitor::adorn_totals("row")cat("\n\n--- Siniestralidad Observada por Quintil de Riesgo ---\n")
--- Siniestralidad Observada por Quintil de Riesgo ---
knitr::kable(resumen_siniestralidad, digits =2,caption ="Frecuencia de Siniestros Observada por Quintil de Riesgo")
Frecuencia de Siniestros Observada por Quintil de Riesgo
grupo_riesgo
N_Polizas
N_Siniestros
Frecuencia_Observada_x_1000
1
19612
96
4.89
2
19612
306
15.60
3
19612
569
29.01
4
19611
1106
56.40
5
19611
2320
118.30
Total
98058
4397
224.21
# --- Lift Chart (Curva de Ganancia) ---calcular_datos_lift <-function(datos, col_pred, col_real) { datos %>% dplyr::select(predicho =!!sym(col_pred), real =!!sym(col_real)) %>%filter(!is.na(predicho) &is.finite(predicho)) %>%arrange(desc(predicho)) %>%mutate(porc_siniestros =cumsum(real) /sum(real),poblacion_acumulada =row_number() /n() ) %>%group_by(decil =ntile(predicho, 10)) %>%summarise(max_porc_siniestros =max(porc_siniestros, na.rm =TRUE),max_poblacion_acumulada =max(poblacion_acumulada, na.rm =TRUE),.groups ='drop' )}# Lista de modelos para compararlista_preds <-c("prediccion_glm_base", "prediccion_glm_enet", "prediccion_rf_enet", "prediccion_glm_indices", "prediccion_rf_indices")nombres_modelos <-c("GLM Base", "GLM (Elastic Net)", "RF (Elastic Net)", "GLM (Índices)", "RF (Índices)")colores_modelos <-c("gray", "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78")names(colores_modelos) <- nombres_modelosdatos_lift_total <- purrr::map_dfr(lista_preds, ~calcular_datos_lift(datos_resultados, .x, "siniestros_reales"), .id ="modelo_id") %>%mutate(modelo_nombre =factor(nombres_modelos[as.integer(modelo_id)], levels = nombres_modelos))# Gráfico con formato de leyenda ajustadoggplot(datos_lift_total, aes(x = max_poblacion_acumulada, y = max_porc_siniestros, color = modelo_nombre, linetype = modelo_nombre)) +geom_line(linewidth =1.2) +geom_segment(aes(x =0, y =0, xend =1, yend =1), color ="white", linetype ="dashed") +scale_color_manual(values = colores_modelos, name ="Estrategia de Modelado") +scale_linetype_manual(values =c("solid", "solid", "dashed", "solid", "dashed"), name ="Estrategia de Modelado") +scale_x_continuous(labels = scales::percent, name ="% Acumulado de Cartera (Ordenada por Riesgo)") +scale_y_continuous(labels = scales::percent, name ="% Acumulado de Siniestros Capturados") +labs(title ="Lift Chart: Comparación de Rutas de Modelado",subtitle ="Elastic Net (Azules) vs. Índices de Comportamiento (Naranjas)") +theme_light(base_size =14) +theme(plot.title =element_text(hjust =0.5, face ="bold"), plot.subtitle =element_text(hjust =0.5),legend.position ="bottom",# CORRECCIÓN: Se ajusta el tamaño de la fuente de la leyendalegend.title =element_text(size =10),legend.text =element_text(size =8) )
6. Conclusiones e Interpretación de Resultados
Al analizar los resultados de ambas rutas de modelado, podemos extraer varias conclusiones clave:
Validación del Poder Predictivo: La tabla de impacto financiero muestra un resultado excelente. El “Costo Observado” aumenta de manera constante y significativa a través de los quintiles de riesgo (de 25.84 en el grupo 1 a 344.56 en el grupo 5). Esto demuestra que los modelos telemáticos son altamente efectivos para segmentar la cartera; los grupos de riesgo que creamos reflejan una diferencia real y material en la siniestralidad.
Calibración de los Modelos: Todos los modelos (excepto el GLM Base) hacen un buen trabajo al predecir el costo promedio dentro de cada quintil, y sus totales se acercan mucho al “Costo Observado” total. Esto indica que los modelos no solo ordenan bien el riesgo, sino que también están bien calibrados a nivel de cartera.
El Valor de la Telemática es Innegable: Como se vio en análisis anteriores y se confirma aquí, todos los modelos que incorporan variables telemáticas (Ruta A y Ruta B) superan drásticamente al GLM Base. El Lift Chart es la evidencia más clara, mostrando que los modelos telemáticos identifican el riesgo mucho antes.
Rendimiento Predictivo Similar, Ventaja en Interpretabilidad:
Ruta A (Elastic Net): Ofrece un rendimiento predictivo muy sólido. El modelo GLM (Elastic Net) y el RF (Elastic Net) siguen de cerca la siniestralidad observada. Su desventaja es la complejidad; el modelo se basa en una lista de variables seleccionadas algorítmicamente que puede ser difícil de explicar en términos de negocio.
Ruta B (Índices): Logra un rendimiento predictivo prácticamente idéntico al de la Ruta A, como se ve en las predicciones del GLM (Índices) y RF (Índices). Sin embargo, su ventaja estratégica es inmensa. Nos permite afirmar con confianza que factores como la “agresividad” (frenazos/acelerones) o el “patrón semanal” (cuándo se conduce) son los verdaderos impulsores del riesgo. Esta narrativa es mucho más potente para la toma de decisiones.
Conclusión Final: Si el único objetivo fuera la máxima precisión, ambas rutas serían casi indistinguibles. Sin embargo, en un contexto de negocio real donde la explicabilidad, la implementación y la comunicación son cruciales, el enfoque con índices de comportamiento (Ruta B) es claramente superior. Proporciona el mismo poder predictivo pero con una capa de interpretabilidad que lo convierte en una herramienta estratégica mucho más valiosa.
7. Mejoras Futuras y Próximos Pasos
Este análisis, aunque robusto, puede ser el punto de partida para exploraciones aún más sofisticadas.
7.1. Modelado Geoespacial
Concepto: El riesgo no es uniforme en el espacio. Conducir en una zona urbana densa con intersecciones complejas es inherentemente más riesgoso que en una autopista rural. Si tuviéramos datos de latitud y longitud, podríamos enriquecer el modelo con variables como: * Tipo de vía (autopista, calle urbana, zona rural). * Densidad de tráfico histórica en la zona. * Proximidad a zonas con alta siniestralidad (puntos negros).
Camino a Seguir en R: * Paquetes:sf (para manejar datos espaciales), sp, gstat (para análisis geoestadístico), y leaflet (para visualizaciones interactivas). * Proceso: 1. Convertir los datos de puntos (lat, lon) a objetos espaciales con sf. 2. Cruzar estos datos con capas de información geográfica (mapas de carreteras, datos de tráfico) para crear nuevas características. 3. Incluir estas nuevas variables geoespaciales en los modelos de frecuencia.
7.2. Análisis de Series Temporales
Concepto: El comportamiento de un conductor no es estático. Un conductor puede mejorar con el tiempo (gracias a la retroalimentación) o empeorar. Analizar las variables telemáticas como series temporales podría revelar tendencias importantes. * ¿La agresividad de un conductor aumenta los viernes por la tarde? * ¿Un conductor muestra una tendencia a la baja en eventos de frenado brusco después de los primeros tres meses del programa?
Camino a Seguir en R: * Paquetes:tsibble y fable (para un manejo moderno de series temporales), prophet (de Facebook, para pronósticos robustos). * Proceso: 1. Reestructurar los datos para que tengan un formato de serie temporal (ej. eventos por día o por semana). 2. Descomponer la serie para identificar tendencias, estacionalidad y ruido. 3. Crear características basadas en estas tendencias (ej. la pendiente de la tendencia de agresividad) para incluirlas en el modelo principal.
7.3. Enfoques con Deep Learning
Concepto: Los modelos como GLM o Random Forest requieren que nosotros hagamos la ingeniería de características. Las redes neuronales, especialmente las diseñadas para datos secuenciales, pueden aprender estas características por sí mismas a partir de los datos crudos. * Redes Neuronales Recurrentes (RNN) y LSTMs: Son ideales para analizar secuencias, como los datos de un viaje segundo a segundo (velocidad, aceleración, etc.). Podrían aprender patrones complejos que son invisibles con la agregación manual.
Camino a Seguir en R: * Paquetes:keras y tensorflow (interfaces de R para las populares librerías de Deep Learning). * Proceso: 1. Preparar los datos telemáticos crudos como secuencias (ej. cada viaje es una secuencia de longitud variable). 2. Diseñar y entrenar una arquitectura de red (ej. una LSTM) para que, a partir de la secuencia del viaje, prediga la probabilidad de siniestro. 3. El resultado de este modelo de Deep Learning podría usarse como un “puntaje telemático” ultra sofisticado en un modelo final.
Source Code
---title: "Análisis Extendido de Tarificación Telemática: Un Enfoque Dual con Índices de Comportamiento"author: "AC (Versión Mejorada)"date: "`r Sys.Date()`"format: html: toc: true toc_float: true code-tools: true theme: darklyeditor: visual---# 1. Introducción al Análisis de Tarificación Telemática## 1.1. ¿Qué es la Tarificación Telemática?La **tarificación telemática**, también conocida como "pago por uso" (Pay-As-You-Drive) o "pago por cómo se conduce" (Pay-How-You-Drive), es un paradigma innovador en el sector de los seguros de automóviles. En lugar de basar las primas únicamente en factores demográficos y de historial tradicionales (edad, sexo, lugar de residencia, historial de siniestros), la telemática incorpora datos en tiempo real sobre el comportamiento de conducción.Mediante dispositivos instalados en el vehículo o aplicaciones móviles, se recopila información detallada como la velocidad, los patrones de aceleración y frenado, los giros, las distancias recorridas y los horarios de conducción. Estos datos permiten a las aseguradoras crear un perfil de riesgo mucho más preciso y personalizado para cada conductor, recompensando los hábitos de conducción seguros con primas más bajas y, a la inversa, ajustando las tarifas para los conductores de mayor riesgo.## 1.2. El Dataset: `catelematic13` de CASdatasetsPara este análisis, utilizaremos el conjunto de datos `catelematic13`, disponible en el paquete de R `CASdatasets`. Este dataset proviene de una aseguradora canadiense y contiene información de una cartera de pólizas de automóviles donde se ha implementado un programa telemático. Es un recurso excelente para explorar cómo los datos de comportamiento pueden complementar los factores de tarificación tradicionales.### Variables Clave en el DatasetEl conjunto de datos se compone de tres grandes grupos de variables:* **Variables Demográficas del Asegurado:** * `InsuredAge`, `InsuredSex`, `Marital`: Edad, sexo y estado civil del conductor.* **Variables del Vehículo:** * `CarAge`, `CarUse`, `Region`: Antigüedad, uso principal (privado o comercial) y región de circulación del vehículo.* **Variables Telemáticas y de Exposición:** * `TotalMilesDriven`: Millas totales conducidas durante el período de observación. * Variables `PctDrive...`: Porcentaje del tiempo de conducción distribuido por día de la semana, hora del día (ej. `PctDriveRushAM` para hora punta matutina) y franjas horarias. * Variables `Accel...`, `Brake...`, `LeftTurn...`, `RightTurn...`: Conteos de eventos de aceleración, frenado y giros, categorizados por su intensidad (ej. `Accel.0.2.0.4` se refiere a eventos de aceleración de intensidad media-baja).* **Variable Objetivo:** * `NbClaim`, `AmtClaim`: Número de siniestros y monto total de los mismos, que son las variables que buscamos predecir.## 1.3. Enfoque de Modelado: Tradicional vs. Índices de ComportamientoEste informe implementará y comparará dos metodologías de modelado para evaluar el impacto de las variables telemáticas:1. **Ruta A - Enfoque Tradicional con Selección de Variables:** * Se realiza una ingeniería de características básica (ej. `frenos_por_milla`). * Se utiliza una técnica de regularización, **Elastic Net**, para seleccionar automáticamente el subconjunto de variables (demográficas y telemáticas) más predictivo de entre un gran número de candidatos. * Este enfoque es potente pero puede carecer de interpretabilidad, ya que la selección es puramente algorítmica.2. **Ruta B - Enfoque Sofisticado con Índices de Comportamiento:** * Se agrupan las variables telemáticas en "dimensiones" lógicas de riesgo (ej. Agresividad, Patrón de Uso). * Se construyen **índices** para cada dimensión. Cada índice es en sí mismo un pequeño modelo que resume el riesgo de esa faceta del comportamiento en un solo número. * Este enfoque es más interpretable, ya que permite al analista entender qué *tipos* de comportamiento son más relevantes para el riesgo, en lugar de solo identificar variables individuales.### Ventajas del Enfoque con ÍndicesEl enfoque de índices (Ruta B) ofrece varias ventajas clave, especialmente en el contexto actuarial:* **Interpretabilidad Mejorada:** Es más fácil explicar al negocio o a un regulador que el "índice de agresividad" de un conductor es alto, que explicar el impacto de diez variables individuales de aceleración y frenado.* **Robustez:** Al promediar la señal de múltiples variables, los índices tienden a ser más estables y menos sensibles al ruido que las variables individuales.* **Reducción de Dimensionalidad Inteligente:** Simplifica el modelo final de una manera guiada por el conocimiento del negocio, no solo por optimización matemática.A lo largo de este documento, desarrollaremos ambas rutas y compararemos sus resultados para determinar qué enfoque ofrece el mejor equilibrio entre poder predictivo y valor de negocio.```{r setup, include=FALSE}# Opciones generales del chunkknitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE)# --- INSTALACIÓN Y CARGA DE PAQUETES ---paquetes <- c("dplyr", "ggplot2", "scales", "knitr", "CASdatasets", "glmnet", "janitor", "patchwork", "randomForest", "tidyr", "corrplot", "MASS")# Cargar paquetesinvisible(lapply(paquetes, library, character.only = TRUE))```# 2. Carga y Preparación de DatosEl proceso comienza con la carga del dataset, seguido de una limpieza estándar para asegurar la calidad de los datos y la creación de variables objetivo fundamentales.```{r preparacion-datos}# Carga de datosdata("catelematic13", package = "CASdatasets")# Limpieza y preparación inicialdatos_base <- catelematic13 %>% janitor::clean_names() %>% # TRADUCCIÓN: Renombrar solo las columnas principales a español para mayor claridad y robustez. dplyr::rename( n_siniestros = nb_claim, monto_siniestro = amt_claim, millas_totales_conducidas = total_miles_driven, edad_asegurado = insured_age, sexo_asegurado = insured_sex, estado_civil = marital, antiguedad_vehiculo = car_age, uso_vehiculo = car_use, region = region ) %>% filter(millas_totales_conducidas > 0, antiguedad_vehiculo >= 0, monto_siniestro >= 0) %>% mutate( across(where(is.character), as.factor), tasa_frecuencia = n_siniestros / millas_totales_conducidas, indicador_siniestro = ifelse(n_siniestros > 0, 1, 0) )# Vista previa de los datoshead(datos_base)```# 3. Análisis Descriptivo AmpliadoAntes de modelar, es crucial entender la distribución de las variables y su relación con la siniestralidad.## 3.1. Variables Demográficas y del Vehículo### Gráficos de Densidad para Variables Continuas```{r graficos-densidad}# Densidad de la Edad del Aseguradop1 <- ggplot(datos_base, aes(x = edad_asegurado)) + geom_density(fill = "#0275D8", alpha = 0.7) + labs(title = "Distribución de la Edad del Asegurado", x = "Edad", y = "Densidad") + theme_light()# Densidad de la Antigüedad del Vehículop2 <- ggplot(datos_base, aes(x = antiguedad_vehiculo)) + geom_density(fill = "#5CB85C", alpha = 0.7) + labs(title = "Distribución de la Antigüedad del Vehículo", x = "Antigüedad (Años)", y = "Densidad") + theme_light()# Combinar gráficosp1 + p2```### Gráficos de Barras para Variables Categóricas```{r graficos-categoricos}# Función auxiliar para gráficos de frecuencia mediaplot_freq_media <- function(data, var) { data %>% group_by({{var}}) %>% summarise(freq_media = mean(tasa_frecuencia) * 1000, n = n()) %>% filter(n > 30) %>% ggplot(aes(x = reorder({{var}}, -freq_media), y = freq_media)) + geom_col(fill = "#D9534F") + labs(y = "Frecuencia Media (/1000 millas)", x = "") + theme_light() + theme(axis.text.x = element_text(angle = 45, hjust = 1))}# Frecuencia por Región y Uso del Vehículop_region <- plot_freq_media(datos_base, region) + labs(title = "Frecuencia por Región")p_uso <- plot_freq_media(datos_base, uso_vehiculo) + labs(title = "Frecuencia por Uso del Vehículo")p_region + p_uso```# 4. Ingeniería de CaracterísticasSe preparan las variables telemáticas para el modelado. Este es el punto donde nuestras dos rutas de análisis divergen.```{r ingenieria-caracteristicas-base}# --- Ingeniería de Características Común para Ambas Rutas ---datos_ingenieria <- datos_base %>% mutate( aceleraciones_totales = rowSums(dplyr::select(., starts_with("accel_")), na.rm = TRUE), frenadas_totales = rowSums(dplyr::select(., starts_with("brake_")), na.rm = TRUE), giros_totales = rowSums(dplyr::select(., starts_with("left_turn_"), starts_with("right_turn_")), na.rm = TRUE), pct_manejo_punta_total = pct_drive_rush_am + pct_drive_rush_pm, frenadas_por_milla = frenadas_totales / millas_totales_conducidas, aceleraciones_por_milla = aceleraciones_totales / millas_totales_conducidas, giros_por_milla = giros_totales / millas_totales_conducidas )```---# **RUTA A: ENFOQUE TRADICIONAL CON ELASTIC NET**En esta ruta, utilizaremos un conjunto amplio de características y dejaremos que un algoritmo de regularización, Elastic Net, seleccione las más importantes.## 4.1.A. Selección de Variables con Elastic Net**Concepto:** Elastic Net es un modelo de regresión que penaliza la complejidad del modelo, forzando a que los coeficientes de las variables menos importantes se reduzcan a cero. Es una mezcla de las penalizaciones Lasso (que es buena para la selección de variables) y Ridge (que es buena para manejar predictores correlacionados). El resultado es un modelo más simple y robusto.```{r elastic-net}# Preparar datos para Elastic Netvars_predictoras_A <- datos_ingenieria %>% dplyr::select( # Demográficas edad_asegurado, sexo_asegurado, antiguedad_vehiculo, estado_civil, region, uso_vehiculo, # Telemáticas de Ingeniería aceleraciones_totales, frenadas_totales, giros_totales, pct_manejo_punta_total, frenadas_por_milla, aceleraciones_por_milla, giros_por_milla, # Telemáticas originales de % de uso (nombres originales) starts_with("pct_drive_") )matriz_x_A <- model.matrix(~ . - 1, data = vars_predictoras_A)vector_y_A <- datos_ingenieria$n_siniestrosoffset_A <- log(datos_ingenieria$millas_totales_conducidas)# Ajustar Elastic Net con validación cruzadaset.seed(123)ajuste_enet <- cv.glmnet(matriz_x_A, vector_y_A, family = "poisson", offset = offset_A, alpha = 0.5)# Extraer las variables seleccionadas (coeficientes no nulos)coeficientes_enet <- coef(ajuste_enet, s = "lambda.1se")vars_seleccionadas_enet <- rownames(coeficientes_enet)[coeficientes_enet[, 1] != 0]# Excluir el interceptovars_seleccionadas_enet <- vars_seleccionadas_enet[vars_seleccionadas_enet != "(Intercept)"]cat("--- Variables Seleccionadas por Elastic Net ---\n")print(vars_seleccionadas_enet)```## 4.2.A. Modelado con Variables SeleccionadasAhora, ajustamos los modelos finales usando solo el conjunto de predictores que Elastic Net consideró relevantes.### Modelos Utilizados* **GLM (Modelo Lineal Generalizado):** Es la extensión de la regresión lineal para variables de respuesta que no siguen una distribución normal (como nuestro conteo de siniestros). Usamos una familia Poisson, adecuada para datos de conteo. Es simple, rápido y muy interpretable.* **Random Forest:** Es un modelo de ensamblaje que construye múltiples árboles de decisión y promedia sus predicciones. Es muy potente, captura interacciones complejas y es robusto al sobreajuste. Su desventaja es que es una "caja negra", menos interpretable que un GLM.```{r modelado-A}# Las predicciones del modelo GLM se harán directamente desde el objeto 'ajuste_enet'.# Fórmula para Random Forest# Es necesario recrear un dataframe con las variables seleccionadas por enet# ya que RF no puede usar la matriz directamente de la misma forma.datos_para_rf_enet <- as.data.frame(as.matrix(matriz_x_A[, vars_seleccionadas_enet]))datos_para_rf_enet$tasa_frecuencia <- datos_ingenieria$tasa_frecuenciaformula_rf_enet <- as.formula(paste("tasa_frecuencia ~ ."))modelo_rf_enet <- randomForest::randomForest(formula_rf_enet, data = datos_para_rf_enet, ntree = 50)```---# **RUTA B: ENFOQUE SOFISTICADO CON ÍNDICES**En esta ruta, creamos nuestros propios predictores de alto nivel (índices) basados en el conocimiento del negocio.## 4.1.B. Creación de Índices de Comportamiento**Concepto:** En lugar de tratar cada variable telemática por separado, las agrupamos en dimensiones lógicas (Agresividad, Patrón de Uso, etc.). Para cada dimensión, ajustamos un mini-modelo GLM para predecir la siniestralidad. La predicción de este modelo, estandarizada, se convierte en nuestro "índice", un único y potente predictor que resume esa faceta del comportamiento.```{r creacion-indices-B}# Función Auxiliar para Crear Índicescrear_indice <- function(data, vars_dimension) { if (length(vars_dimension) == 0) return(rep(0, nrow(data))) formula_dim <- as.formula(paste("n_siniestros ~", paste(vars_dimension, collapse = " + "), "+ offset(log(millas_totales_conducidas))")) modelo_dim <- glm(formula_dim, data = data, family = poisson(link = "log")) indice_bruto <- predict(modelo_dim, type = "response") / data$millas_totales_conducidas if (sd(indice_bruto, na.rm = TRUE) > 1e-6) return(as.numeric(scale(indice_bruto))) else return(rep(0, length(indice_bruto)))}# Definir Dimensiones y Crear los Índicesvars_agresividad <- c("frenadas_por_milla", "aceleraciones_por_milla")vars_curvas <- c("giros_por_milla")vars_patron_horario <- c("pct_manejo_punta_total")# Se usan los nombres originales de las columnas, que empiezan con 'pct_drive_'vars_patron_semanal <- names(datos_ingenieria)[grepl("^pct_drive_(mon|tue|th|fri|sat|sun)$", names(datos_ingenieria))]datos_con_indices <- datos_ingenieria %>% mutate( indice_agresividad = crear_indice(., vars_agresividad), indice_curvas = crear_indice(., vars_curvas), indice_patron_horario = crear_indice(., vars_patron_horario), indice_patron_semanal = crear_indice(., vars_patron_semanal) )summary(dplyr::select(datos_con_indices, starts_with("indice_")))```## 4.2.B. Análisis Descriptivo de los ÍndicesVerificamos que nuestros índices no estén demasiado correlacionados, lo que confirmaría que miden aspectos distintos del riesgo. El `índice_patron_horario` muestra una varianza nula, lo que significa que la variable `pct_manejo_punta_total` no tiene poder predictivo por sí sola en este contexto y será excluida de los modelos.```{r analisis-indices-B}# Filtrar índices con varianza cero antes de graficarindices_para_analisis <- datos_con_indices %>% dplyr::select(starts_with("indice_")) %>% dplyr::select(where(~ sd(.x, na.rm = TRUE) > 1e-6))# Gráfico de Cajas (Box Plot) para visualizar la distribuciónif (ncol(indices_para_analisis) > 0) { plot_cajas <- indices_para_analisis %>% tidyr::pivot_longer(everything(), names_to = "indice", values_to = "valor") %>% ggplot(aes(x = indice, y = valor, fill = indice)) + geom_boxplot() + labs(title = "Distribución de los Índices de Comportamiento", x = "Índice", y = "Valor Estandarizado") + theme_light() + theme(legend.position = "none", axis.text.x = element_text(angle = 45, hjust = 1)) print(plot_cajas)} else { cat("No hay índices con varianza para graficar su distribución.\n")}```## 4.3.B. Modelado con ÍndicesAjustamos los mismos tipos de modelos (GLM y Random Forest), pero esta vez usando nuestros índices de alto nivel como predictores.```{r modelado-B}# Preparar Fórmulasvariables_demograficas <- c("edad_asegurado", "sexo_asegurado", "antiguedad_vehiculo", "estado_civil", "region", "uso_vehiculo")variables_indices <- names(indices_para_analisis)predictores_indices <- c(variables_demograficas, variables_indices)formula_indices_texto <- paste(predictores_indices, collapse = " + ")formula_base_texto <- paste(variables_demograficas, collapse = " + ")# Modelo 1: GLM Base (común a ambas rutas, solo demografía)modelo_glm_base <- glm(as.formula(paste("n_siniestros ~", formula_base_texto, "+ offset(log(millas_totales_conducidas))")), data = datos_con_indices, family = poisson(link = "log"))# Modelo 2B: GLM con Índicesmodelo_glm_indices <- glm(as.formula(paste("n_siniestros ~", formula_indices_texto, "+ offset(log(millas_totales_conducidas))")), data = datos_con_indices, family = poisson(link = "log"))# Modelo 3B: Random Forest con Índicesformula_rf_indices <- as.formula(paste("tasa_frecuencia ~", formula_indices_texto))modelo_rf_indices <- randomForest::randomForest(formula_rf_indices, data = datos_con_indices, ntree = 50)```# 5. Evaluación de Resultados y Comparación de RutasAhora comparamos el rendimiento de todos los modelos de ambas rutas.## 5.1. Criterios de Decisión y su Interpretación* **Tabla de Impacto Financiero:** Comparamos el "Costo Observado" (la prima pura real) con el costo predicho por cada modelo, agrupando a los asegurados por nivel de riesgo. Un buen modelo tendrá predicciones cercanas a los valores observados en cada grupo.* **Lift Chart (Curva de Ganancia):** Esta gráfica muestra la capacidad de un modelo para separar a los clientes de alto riesgo de los de bajo riesgo. Una curva que sube rápidamente y se aleja de la diagonal indica un modelo con un alto poder predictivo. Por ejemplo, si la curva muestra que el 20% de la cartera de mayor riesgo (según el modelo) concentra el 50% de los siniestros, el modelo es muy eficiente.```{r evaluacion-resultados}# --- Generación de Predicciones ---datos_resultados <- datos_con_indices %>% mutate( prediccion_glm_base = predict(modelo_glm_base, type = "response"), # Ruta A prediccion_glm_enet = as.numeric(predict(ajuste_enet, newx = matriz_x_A, s = "lambda.1se", type = "response", newoffset = offset_A)), prediccion_rf_enet = predict(modelo_rf_enet, newdata = datos_para_rf_enet) * millas_totales_conducidas, # Ruta B prediccion_glm_indices = predict(modelo_glm_indices, type = "response"), prediccion_rf_indices = predict(modelo_rf_indices, type = "response") * millas_totales_conducidas, siniestros_reales = n_siniestros )# --- Impacto Financiero por Grupo de Riesgo ---severidad_promedio <- sum(datos_resultados$monto_siniestro) / sum(datos_resultados$siniestros_reales, na.rm = TRUE)datos_resultados <- datos_resultados %>% mutate(grupo_riesgo = ntile(prediccion_glm_indices, 5)) # Usamos el modelo de índices como referenciaresumen_impacto <- datos_resultados %>% group_by(grupo_riesgo) %>% summarise( Costo_Observado = sum(monto_siniestro) / n(), Costo_Pred_GLM_Base = mean(prediccion_glm_base * severidad_promedio, na.rm=T), Costo_Pred_GLM_ENet = mean(prediccion_glm_enet * severidad_promedio, na.rm=T), Costo_Pred_RF_ENet = mean(prediccion_rf_enet * severidad_promedio, na.rm=T), Costo_Pred_GLM_Indices = mean(prediccion_glm_indices * severidad_promedio, na.rm=T), Costo_Pred_RF_Indices = mean(prediccion_rf_indices * severidad_promedio, na.rm=T), .groups = 'drop' ) %>% janitor::adorn_totals("row")cat("\n--- Comparación de Impacto Financiero por Quintil de Riesgo ---\n")knitr::kable(resumen_impacto, digits = 2, caption = "Costo Promedio (Prima Pura) por Quintil de Riesgo")# --- NUEVA TABLA: Siniestralidad por Grupo de Riesgo ---resumen_siniestralidad <- datos_resultados %>% group_by(grupo_riesgo) %>% summarise( N_Polizas = n(), N_Siniestros = sum(siniestros_reales), Frecuencia_Observada_x_1000 = (N_Siniestros / N_Polizas) * 1000 ) %>% janitor::adorn_totals("row")cat("\n\n--- Siniestralidad Observada por Quintil de Riesgo ---\n")knitr::kable(resumen_siniestralidad, digits = 2, caption = "Frecuencia de Siniestros Observada por Quintil de Riesgo")# --- Lift Chart (Curva de Ganancia) ---calcular_datos_lift <- function(datos, col_pred, col_real) { datos %>% dplyr::select(predicho = !!sym(col_pred), real = !!sym(col_real)) %>% filter(!is.na(predicho) & is.finite(predicho)) %>% arrange(desc(predicho)) %>% mutate( porc_siniestros = cumsum(real) / sum(real), poblacion_acumulada = row_number() / n() ) %>% group_by(decil = ntile(predicho, 10)) %>% summarise( max_porc_siniestros = max(porc_siniestros, na.rm = TRUE), max_poblacion_acumulada = max(poblacion_acumulada, na.rm = TRUE), .groups = 'drop' )}# Lista de modelos para compararlista_preds <- c("prediccion_glm_base", "prediccion_glm_enet", "prediccion_rf_enet", "prediccion_glm_indices", "prediccion_rf_indices")nombres_modelos <- c("GLM Base", "GLM (Elastic Net)", "RF (Elastic Net)", "GLM (Índices)", "RF (Índices)")colores_modelos <- c("gray", "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78")names(colores_modelos) <- nombres_modelosdatos_lift_total <- purrr::map_dfr(lista_preds, ~calcular_datos_lift(datos_resultados, .x, "siniestros_reales"), .id = "modelo_id") %>% mutate(modelo_nombre = factor(nombres_modelos[as.integer(modelo_id)], levels = nombres_modelos))# Gráfico con formato de leyenda ajustadoggplot(datos_lift_total, aes(x = max_poblacion_acumulada, y = max_porc_siniestros, color = modelo_nombre, linetype = modelo_nombre)) + geom_line(linewidth = 1.2) + geom_segment(aes(x = 0, y = 0, xend = 1, yend = 1), color = "white", linetype = "dashed") + scale_color_manual(values = colores_modelos, name = "Estrategia de Modelado") + scale_linetype_manual(values = c("solid", "solid", "dashed", "solid", "dashed"), name = "Estrategia de Modelado") + scale_x_continuous(labels = scales::percent, name = "% Acumulado de Cartera (Ordenada por Riesgo)") + scale_y_continuous(labels = scales::percent, name = "% Acumulado de Siniestros Capturados") + labs(title = "Lift Chart: Comparación de Rutas de Modelado", subtitle = "Elastic Net (Azules) vs. Índices de Comportamiento (Naranjas)") + theme_light(base_size = 14) + theme( plot.title = element_text(hjust = 0.5, face = "bold"), plot.subtitle = element_text(hjust = 0.5), legend.position = "bottom", # CORRECCIÓN: Se ajusta el tamaño de la fuente de la leyenda legend.title = element_text(size = 10), legend.text = element_text(size = 8) )```# 6. Conclusiones e Interpretación de ResultadosAl analizar los resultados de ambas rutas de modelado, podemos extraer varias conclusiones clave:1. **Validación del Poder Predictivo:** La tabla de impacto financiero muestra un resultado excelente. El "Costo Observado" aumenta de manera constante y significativa a través de los quintiles de riesgo (de 25.84 en el grupo 1 a 344.56 en el grupo 5). Esto demuestra que los modelos telemáticos son **altamente efectivos para segmentar la cartera**; los grupos de riesgo que creamos reflejan una diferencia real y material en la siniestralidad.2. **Calibración de los Modelos:** Todos los modelos (excepto el GLM Base) hacen un buen trabajo al predecir el costo promedio dentro de cada quintil, y sus totales se acercan mucho al "Costo Observado" total. Esto indica que los modelos no solo ordenan bien el riesgo, sino que también están bien calibrados a nivel de cartera.3. **El Valor de la Telemática es Innegable:** Como se vio en análisis anteriores y se confirma aquí, todos los modelos que incorporan variables telemáticas (Ruta A y Ruta B) superan drásticamente al `GLM Base`. El Lift Chart es la evidencia más clara, mostrando que los modelos telemáticos identifican el riesgo mucho antes.4. **Rendimiento Predictivo Similar, Ventaja en Interpretabilidad:** * **Ruta A (Elastic Net):** Ofrece un rendimiento predictivo muy sólido. El modelo GLM (Elastic Net) y el RF (Elastic Net) siguen de cerca la siniestralidad observada. Su desventaja es la complejidad; el modelo se basa en una lista de variables seleccionadas algorítmicamente que puede ser difícil de explicar en términos de negocio. * **Ruta B (Índices):** Logra un rendimiento predictivo prácticamente idéntico al de la Ruta A, como se ve en las predicciones del `GLM (Índices)` y `RF (Índices)`. Sin embargo, su **ventaja estratégica es inmensa**. Nos permite afirmar con confianza que factores como la "agresividad" (frenazos/acelerones) o el "patrón semanal" (cuándo se conduce) son los verdaderos impulsores del riesgo. Esta narrativa es mucho más potente para la toma de decisiones.**Conclusión Final:** Si el único objetivo fuera la máxima precisión, ambas rutas serían casi indistinguibles. Sin embargo, en un contexto de negocio real donde la **explicabilidad, la implementación y la comunicación** son cruciales, **el enfoque con índices de comportamiento (Ruta B) es claramente superior**. Proporciona el mismo poder predictivo pero con una capa de interpretabilidad que lo convierte en una herramienta estratégica mucho más valiosa.# 7. Mejoras Futuras y Próximos PasosEste análisis, aunque robusto, puede ser el punto de partida para exploraciones aún más sofisticadas.### 7.1. Modelado Geoespacial**Concepto:** El riesgo no es uniforme en el espacio. Conducir en una zona urbana densa con intersecciones complejas es inherentemente más riesgoso que en una autopista rural. Si tuviéramos datos de latitud y longitud, podríamos enriquecer el modelo con variables como:* Tipo de vía (autopista, calle urbana, zona rural).* Densidad de tráfico histórica en la zona.* Proximidad a zonas con alta siniestralidad (puntos negros).**Camino a Seguir en R:*** **Paquetes:** `sf` (para manejar datos espaciales), `sp`, `gstat` (para análisis geoestadístico), y `leaflet` (para visualizaciones interactivas).* **Proceso:** 1. Convertir los datos de puntos (lat, lon) a objetos espaciales con `sf`. 2. Cruzar estos datos con capas de información geográfica (mapas de carreteras, datos de tráfico) para crear nuevas características. 3. Incluir estas nuevas variables geoespaciales en los modelos de frecuencia.### 7.2. Análisis de Series Temporales**Concepto:** El comportamiento de un conductor no es estático. Un conductor puede mejorar con el tiempo (gracias a la retroalimentación) o empeorar. Analizar las variables telemáticas como series temporales podría revelar tendencias importantes.* ¿La agresividad de un conductor aumenta los viernes por la tarde?* ¿Un conductor muestra una tendencia a la baja en eventos de frenado brusco después de los primeros tres meses del programa?**Camino a Seguir en R:*** **Paquetes:** `tsibble` y `fable` (para un manejo moderno de series temporales), `prophet` (de Facebook, para pronósticos robustos).* **Proceso:** 1. Reestructurar los datos para que tengan un formato de serie temporal (ej. eventos por día o por semana). 2. Descomponer la serie para identificar tendencias, estacionalidad y ruido. 3. Crear características basadas en estas tendencias (ej. la pendiente de la tendencia de agresividad) para incluirlas en el modelo principal.### 7.3. Enfoques con Deep Learning**Concepto:** Los modelos como GLM o Random Forest requieren que nosotros hagamos la ingeniería de características. Las redes neuronales, especialmente las diseñadas para datos secuenciales, pueden aprender estas características por sí mismas a partir de los datos crudos.* **Redes Neuronales Recurrentes (RNN) y LSTMs:** Son ideales para analizar secuencias, como los datos de un viaje segundo a segundo (velocidad, aceleración, etc.). Podrían aprender patrones complejos que son invisibles con la agregación manual.**Camino a Seguir en R:*** **Paquetes:** `keras` y `tensorflow` (interfaces de R para las populares librerías de Deep Learning).* **Proceso:** 1. Preparar los datos telemáticos crudos como secuencias (ej. cada viaje es una secuencia de longitud variable). 2. Diseñar y entrenar una arquitectura de red (ej. una LSTM) para que, a partir de la secuencia del viaje, prediga la probabilidad de siniestro. 3. El resultado de este modelo de Deep Learning podría usarse como un "puntaje telemático" ultra sofisticado en un modelo final.