INTRODUCCIÓN MARKETING BANCARIO

En el ámbito de la ciencia de datos, la metodología CRISP-DM (Cross Industry Standard Process for Data Mining) se ha consolidado como un enfoque estándar y ampliamente adoptado para el desarrollo estructurado de proyectos de minería de datos.

En este proyecto, aplicaremos CRISP-DM a una base de datos proveniente de campañas de marketing directo realizadas por una entidad bancaria portuguesa. Dichas campañas se llevaron a cabo a través de llamadas telefónicas con el fin de promover productos financieros, específicamente depósitos a plazo fijo. La base de datos contiene información sociodemográfica de los clientes, así como detalles de sus interacciones previas con la entidad bancaria y los resultados de campañas anteriores.

El objetivo principal de análisis es desarrollar un modelo de clasificación que permita predecir si un cliente suscribirá o no un depósito a plazo (representado por la variable binaria y). Este enfoque permitirá identificar patrones relevantes en los datos y apoyar la toma de decisiones estratégicas en futuras campañas de marketing.

COMPRESIÓN DEL NEGOCIO

Un banco de Portugal realiza campañas de marketing directo (llamadas telefónicas) para promocionar depósitos a plazo entre sus clientes. Actualmente, no cuenta con un sistema predictivo para optimizar estos contactos

Problema empresarial: Altos costos operativos y baja efectividad en las campañas telefónicas para depósitos a plazo, debido a la falta de un sistema que identifique qué clientes tienen mayor probabilidad de suscribir.

Objetivos

Predecir la probabilidad de suscripción de un depósito a plazo (variable y), teniendo en cuenta:

- Datos demográficos (edad, ocupación, educación)

- Situación financiera (saldo, créditos)

- Historial de interacciones (contactos previos, resultados de campañas anteriores)

- Contexto de la llamada (duración, mes, día de contacto)

- Identificar los factores más influyentes en la decisión del cliente.

COMPRESIÓN DE LOS DATOS

MARKETING BANCARIO

library(readxl)
Banco_2 <- read_excel("Banco 2.xlsx")
head(Banco_2)
## # A tibble: 6 × 17
##     age job        marital education default balance housing loan  contact   day
##   <dbl> <chr>      <chr>   <chr>     <chr>     <dbl> <chr>   <chr> <chr>   <dbl>
## 1    58 management married tertiary  no         2143 yes     no    unknown     5
## 2    44 technician single  secondary no           29 yes     no    unknown     5
## 3    33 entrepren… married secondary no            2 yes     yes   unknown     5
## 4    47 blue-coll… married unknown   no         1506 yes     no    unknown     5
## 5    33 unknown    single  unknown   no            1 no      no    unknown     5
## 6    35 management married tertiary  no          231 yes     no    unknown     5
## # ℹ 7 more variables: month <chr>, duration <dbl>, campaign <dbl>, pdays <dbl>,
## #   previous <dbl>, poutcome <chr>, y <chr>

DESCRIPCIÓN DE CADA VARIABLE CUANTITATIVA

Age: Edad del cliente.

Job: Tipo de ocupación (administrativo, tecnico, retirado, etc.).

Marital: Casado, soltero o divorciado/viudo.

Education: Nivel educativo (primaria, secundaria, terciaria, desconocido).

Default: Tiene deudas impagas en créditos anteriores (sí/no).

Balance: Saldo medio anual en euros.

Housing: ¿Tiene préstamo hipotecario? (sí/no).

Loan: ¿Tiene préstamo personal? (sí/no).

Contact: Medio usado para el contacto (teléfono, celular o desconocido).

Day: Día del último contacto (numérico).

Month: Mes del último contacto (ene a dic).

Duration: Duración de la última llamada, en segundos.

Campaign: Número de contactos durante la campaña actual.

Pdays: Días desde el último contacto previo (-1 si nunca fue contactado).

Previus: Número de contactos antes de esta campaña.

Poutcome: Resultado de la campaña anterior (éxito, fracaso, desconocido, otro).

y: Variable objetivo: Indica si contrató un depósito a plazo (sí/no).

# Cargar librerías necesarias
library(readxl)
library(modeest)
## Warning: package 'modeest' was built under R version 4.4.3
# Cargar el archivo Excel
Banco_2 <- read_excel("C:/Users/Sanvi/Downloads/Banco 2.xlsx")

# Calcular estadísticas de edad
media <- mean(Banco_2$age, na.rm = TRUE)
mediana <- median(Banco_2$age, na.rm = TRUE)
moda <- mfv(Banco_2$age, na_rm = TRUE)
cuartiles <- quantile(Banco_2$age, na.rm = TRUE)

# Mostrar resultados
cat("Los resultados de la variable age son:\n")
## Los resultados de la variable age son:
cat("La media es:", media, "\n")
## La media es: 40.93621
cat("La mediana es:", mediana, "\n")
## La mediana es: 39
cat("La moda es:", moda, "\n")
## La moda es: 32
cat("Los cuartiles son:\n")
## Los cuartiles son:
print(cuartiles)
##   0%  25%  50%  75% 100% 
##   18   33   39   48   95
#####

# Cargar librerías necesarias
library(readxl)
library(modeest)

# Leer correctamente el archivo Excel
Banco_2 <- read_excel("C:/Users/Sanvi/Downloads/Banco 2.xlsx")

# Calcular estadísticas para 'balance'
media <- mean(Banco_2$balance, na.rm = TRUE)
mediana <- median(Banco_2$balance, na.rm = TRUE)
moda <- mfv(Banco_2$balance, na_rm = TRUE)
cuartiles <- quantile(Banco_2$balance, na.rm = TRUE)

# Mostrar resultados en consola
cat("Los resultados de la variable balance son:\n")
## Los resultados de la variable balance son:
cat("La media del balance es:", media, "\n")
## La media del balance es: 1362.272
cat("La mediana del balance es:", mediana, "\n")
## La mediana del balance es: 448
cat("La moda del balance es:", moda, "\n")
## La moda del balance es: 0
cat("Los cuartiles del balance son:\n")
## Los cuartiles del balance son:
print(cuartiles)
##     0%    25%    50%    75%   100% 
##  -8019     72    448   1428 102127
library(readxl)
library(modeest)

# Cargar el archivo Excel
Banco_2 <- read_excel("C:/Users/Sanvi/Downloads/Banco 2.xlsx")

# Calcular estadísticas para 'day'
media <- mean(Banco_2$day, na.rm = TRUE)
mediana <- median(Banco_2$day, na.rm = TRUE)
moda <- mfv(Banco_2$day, na_rm = TRUE)
cuartiles <- quantile(Banco_2$day, na.rm = TRUE)

# Imprimir resultados con texto
cat("Los resultados de la variable day son:\n")
## Los resultados de la variable day son:
cat("La media del día es:", media, "\n")
## La media del día es: 15.80642
cat("La mediana del día es:", mediana, "\n")
## La mediana del día es: 16
cat("La moda del día es:", moda, "\n")
## La moda del día es: 20
cat("Los cuartiles del día son:\n")
## Los cuartiles del día son:
print(cuartiles)
##   0%  25%  50%  75% 100% 
##    1    8   16   21   31
library(readxl)
library(modeest)

# Leer el archivo Excel
Banco_2 <- read_excel("C:/Users/Sanvi/Downloads/Banco 2.xlsx")

# Calcular estadísticas para 'duration'
media <- mean(Banco_2$duration, na.rm = TRUE)
mediana <- median(Banco_2$duration, na.rm = TRUE)
moda <- mfv(Banco_2$duration, na_rm = TRUE)
cuartiles <- quantile(Banco_2$duration, na.rm = TRUE)

# Imprimir resultados con texto
cat("Los resultados de la variable duration son:\n")
## Los resultados de la variable duration son:
cat("La media de la duración es:", media, "segundos\n")
## La media de la duración es: 258.1631 segundos
cat("La mediana de la duración es:", mediana, "segundos\n")
## La mediana de la duración es: 180 segundos
cat("La moda de la duración es:", moda, "segundos\n")
## La moda de la duración es: 124 segundos
cat("Los cuartiles de la duración son:\n")
## Los cuartiles de la duración son:
print(cuartiles)
##   0%  25%  50%  75% 100% 
##    0  103  180  319 4918
library(readxl)
library(modeest)

# Leer el archivo Excel
Banco_2 <- read_excel("C:/Users/Sanvi/Downloads/Banco 2.xlsx")

# Calcular estadísticas para 'campaign'
media <- mean(Banco_2$campaign, na.rm = TRUE)
mediana <- median(Banco_2$campaign, na.rm = TRUE)
moda <- mfv(Banco_2$campaign, na_rm = TRUE)
cuartiles <- quantile(Banco_2$campaign, na.rm = TRUE)

# Imprimir resultados con texto
cat("Los resultados de la variable campaign son:\n")
## Los resultados de la variable campaign son:
cat("La media de los contactos en la campaña es:", media, "\n")
## La media de los contactos en la campaña es: 2.763841
cat("La mediana es:", mediana, "\n")
## La mediana es: 2
cat("La moda es:", moda, "\n")
## La moda es: 1
cat("Los cuartiles son:\n")
## Los cuartiles son:
print(cuartiles)
##   0%  25%  50%  75% 100% 
##    1    1    2    3   63
library(readxl)
library(modeest)

# Leer el archivo Excel
Banco_2 <- read_excel("C:/Users/Sanvi/Downloads/Banco 2.xlsx")

# Calcular estadísticas para 'pdays'
media <- mean(Banco_2$pdays, na.rm = TRUE)
mediana <- median(Banco_2$pdays, na.rm = TRUE)
moda <- mfv(Banco_2$pdays, na_rm = TRUE)
cuartiles <- quantile(Banco_2$pdays, na.rm = TRUE)

# Imprimir resultados con texto
cat("Los resultados de la variable pdays son:\n")
## Los resultados de la variable pdays son:
cat("La media de pdays es:", media, "\n")
## La media de pdays es: 40.19783
cat("La mediana es:", mediana, "\n")
## La mediana es: -1
cat("La moda es:", moda, "\n")
## La moda es: -1
cat("Los cuartiles de pdays son:\n")
## Los cuartiles de pdays son:
print(cuartiles)
##   0%  25%  50%  75% 100% 
##   -1   -1   -1   -1  871
# Filtrar valores distintos de -1
pdays_filtrado <- Banco_2$pdays[Banco_2$pdays != -1]

# Calcular estadísticas sin los -1
media <- mean(pdays_filtrado)
mediana <- median(pdays_filtrado)
moda <- mfv(pdays_filtrado)
cuartiles <- quantile(pdays_filtrado)

# Imprimir resultados sin -1
cat("La media de pdays (excluyendo -1) es:", media, "\n")
## La media de pdays (excluyendo -1) es: 224.5777
cat("La mediana es:", mediana, "\n")
## La mediana es: 194
cat("La moda es:", moda, "\n")
## La moda es: 182
cat("Los cuartiles de pdays (sin -1) son:\n")
## Los cuartiles de pdays (sin -1) son:
print(cuartiles)
##   0%  25%  50%  75% 100% 
##    1  133  194  327  871
library(readxl)
library(modeest)

# Leer el archivo Excel
Banco_2 <- read_excel("C:/Users/Sanvi/Downloads/Banco 2.xlsx")

# Calcular estadísticas para 'previous'
media_previous <- mean(Banco_2$previous, na.rm = TRUE)
mediana_previous <- median(Banco_2$previous, na.rm = TRUE)
moda_previous <- mfv(Banco_2$previous, na_rm = TRUE)
cuartiles_previous <- quantile(Banco_2$previous, na.rm = TRUE)

# Imprimir resultados con texto
cat("Los resultados de la variable previous son:\n")
## Los resultados de la variable previous son:
cat("La media de previous es:", media_previous, "\n")
## La media de previous es: 0.5803234
cat("La mediana es:", mediana_previous, "\n")
## La mediana es: 0
cat("La moda es:", moda_previous, "\n")
## La moda es: 0
cat("Los cuartiles de previous son:\n")
## Los cuartiles de previous son:
print(cuartiles_previous)
##   0%  25%  50%  75% 100% 
##    0    0    0    0  275

INTERPRETACIÓN DE CADA VARIABLE

AGE

La edad promedio de los clientes es de 40.9 años, con una mediana de 39 años, lo que indica que la distribución es ligeramente asimétrica hacia edades más altas. La moda es 32 años, lo que significa que esta es la edad más frecuente en la base de datos. El 25% de los clientes tienen 33 años o menos, mientras que el 75% tiene 48 años o menos. Esto sugiere que la mayoría de los clientes están en un rango de edad económicamente activo (30-50 años), con una presencia significativa de personas más jóvenes (32 años como moda).

BALANCE

El saldo promedio en las cuentas es de 1,362 unidades monetarias, pero la mediana es de solo 448, lo que revela una fuerte asimetría positiva debido a algunos clientes con saldos muy altos (hasta 102,127). La moda es 0, lo que indica que muchas cuentas no tienen saldo o están en cero. El 25% de los clientes tienen saldos de 72 o menos, y el 75% tiene saldos de 1,428 o menos. Esto muestra que la mayoría de los clientes tienen saldos bajos, con pocos casos de saldos extremadamente altos que distorsionan la media.

DAY

El día promedio del último contacto es el 15.8 (mitad del mes), con una mediana de 16 y una moda de 20, lo que sugiere que los contactos se concentran hacia finales del mes. El 25% de los clientes fueron contactados antes del día 8, y el 75% antes del día 21. Esto podría indicar que las campañas se intensifican en la segunda quincena, posiblemente para coincidir con períodos de pago o mayor disponibilidad de fondos.

DURATION

La duración promedio de las llamadas es de 258 segundos (4.3 minutos), pero la mediana es de 180 segundos (3 minutos), lo que indica que algunas llamadas muy largas (hasta 4,918 segundos) elevan el promedio. La moda es 124 segundos (~2 minutos), lo que confirma que la mayoría de las llamadas son relativamente cortas. El 25% de las llamadas duran menos de 103 segundos, y el 75% menos de 319 segundos. Esto sugiere que, aunque hay llamadas extensas, la mayoría son breves.

CAMPAIGN

El número promedio de contactos por cliente es de 2.76, con una mediana de 2 y una moda de 1, lo que indica que la mayoría de los clientes fueron contactados una o dos veces. Sin embargo, hay casos extremos (hasta 63 contactos), lo que podría reflejar estrategias de seguimiento agresivas para ciertos clientes. El 75% de los clientes fueron contactados 3 veces o menos, lo que sugiere que, en general, las campañas no son excesivamente intrusivas.

PDAYS

La mayoría de los clientes no fueron contactados previamente (mediana y moda = -1). Entre los que sí fueron contactados, el promedio de días desde el último contacto es de 224.6 (7.5 meses), con una mediana de 194 días (6.5 meses). Esto indica que los contactos previos son poco frecuentes y que la mayoría de las interacciones ocurren en la campaña actual.

PREVIUS

La mayoría de los clientes no tuvieron contactos previos (mediana y moda = 0). El promedio es de 0.58, lo que confirma que las campañas anteriores fueron mínimas o nulas para la mayoría

VARIABLES CATEGORICAS

library(readxl)

# Leer el archivo Excel
Banco_2 <- read_excel("C:/Users/Sanvi/Downloads/Banco 2.xlsx")

# Calcular frecuencia de cada categoría de 'job'
frecuencia_job <- table(Banco_2$job)

# Imprimir los resultados
cat("La frecuencia de cada categoría de 'job' es:\n")
## La frecuencia de cada categoría de 'job' es:
print(frecuencia_job)
## 
##        admin.   blue-collar  entrepreneur     housemaid    management 
##          5171          9732          1487          1240          9458 
##       retired self-employed      services       student    technician 
##          2264          1579          4154           938          7597 
##    unemployed       unknown 
##          1303           288
library(readxl)

# Leer el archivo Excel
Banco_2 <- read_excel("C:/Users/Sanvi/Downloads/Banco 2.xlsx")
# Calcular frecuencia de cada categoría de 'marital'
frecuencia_marital <- table(Banco_2$marital)

# Imprimir los resultados
cat("La frecuencia de cada categoría de 'marital' es:\n")
## La frecuencia de cada categoría de 'marital' es:
print(frecuencia_marital)
## 
## divorced  married   single 
##     5207    27214    12790
library(readxl)

# Leer el archivo Excel
Banco_2 <- read_excel("C:/Users/Sanvi/Downloads/Banco 2.xlsx")

# Calcular frecuencia de cada categoría de 'education'
frecuencia_education <- table(Banco_2$education)

# Imprimir los resultados
cat("La frecuencia de cada categoría de 'education' es:\n")
## La frecuencia de cada categoría de 'education' es:
print(frecuencia_education)
## 
##   primary secondary  tertiary   unknown 
##      6851     23202     13301      1857
library(readxl)

# Leer el archivo Excel
Banco_2 <- read_excel("C:/Users/Sanvi/Downloads/Banco 2.xlsx")

# Calcular frecuencia de cada categoría de 'default'
frecuencia_default <- table(Banco_2$default)

# Imprimir los resultados
cat("La frecuencia de cada categoría de 'default' es:\n")
## La frecuencia de cada categoría de 'default' es:
print(frecuencia_default)
## 
##    no   yes 
## 44396   815
# Calcular frecuencia de cada categoría de 'housing'
frecuencia_housing <- table(Banco_2$housing)

# Imprimir los resultados
cat("La frecuencia de cada categoría de 'housing' es:\n")
## La frecuencia de cada categoría de 'housing' es:
print(frecuencia_housing)
## 
##    no   yes 
## 20081 25130
# Calcular frecuencia de cada categoría de 'loan'
frecuencia_loan <- table(Banco_2$loan)

# Imprimir los resultados
cat("La frecuencia de cada categoría de 'loan' es:\n")
## La frecuencia de cada categoría de 'loan' es:
print(frecuencia_loan)
## 
##    no   yes 
## 37967  7244
# Calcular frecuencia de cada categoría de 'contact'
frecuencia_contact <- table(Banco_2$contact)

# Imprimir los resultados
cat("La frecuencia de cada categoría de 'contact' es:\n")
## La frecuencia de cada categoría de 'contact' es:
print(frecuencia_contact)
## 
##  cellular telephone   unknown 
##     29285      2906     13020
# Calcular frecuencia de cada categoría de 'month'
frecuencia_month <- table(Banco_2$month)

# Imprimir los resultados
cat("La frecuencia de cada categoría de 'month' es:\n")
## La frecuencia de cada categoría de 'month' es:
print(frecuencia_month)
## 
##   apr   aug   dec   feb   jan   jul   jun   mar   may   nov   oct   sep 
##  2932  6247   214  2649  1403  6895  5341   477 13766  3970   738   579
# Calcular frecuencia de cada categoría de 'poutcome'
frecuencia_poutcome <- table(Banco_2$poutcome)

# Imprimir los resultados
cat("La frecuencia de cada categoría de 'poutcome' es:\n")
## La frecuencia de cada categoría de 'poutcome' es:
print(frecuencia_poutcome)
## 
## failure   other success unknown 
##    4901    1840    1511   36959
# Calcular frecuencia de cada categoría de 'y'
frecuencia_y <- table(Banco_2$y)

# Imprimir los resultados
cat("La frecuencia de cada categoría de 'y' es:\n")
## La frecuencia de cada categoría de 'y' es:
print(frecuencia_y)
## 
##    no   yes 
## 39922  5289

INTERPRETACION DE CADA VARIABLE

JOB

La distribución de ocupaciones muestra que los grupos más representados son los trabajadores manuales (blue-collar, 9,732) y los gerentes (management, 9,458), lo que refleja el perfil laboral típico de la base de clientes. Las ocupaciones menos frecuentes son estudiantes (938) y amas de casa (housemaid, 1,240), lo que podría indicar que estos grupos tienen menor interacción con productos bancarios complejos como depósitos a plazo. Destaca la presencia significativa de técnicos (technician, 7,597) y personal administrativo (admin., 5,171), lo que sugiere una base de clientes diversa pero con predominio de empleados formales.

MARITAL

La mayoría de los clientes están casados (27,214), seguidos por solteros (12,790) y divorciados (5,207). Esta distribución podría ser relevante para las estrategias de marketing, ya que las personas casadas suelen tomar decisiones financieras conjuntas y podrían ser más propensas a productos de ahorro a largo plazo. La proporción de divorciados (aproximadamente 11.5%) es significativa y podría representar un segmento con necesidades financieras específicas.

EDUCATION

Predomina la educación secundaria (23,202), seguida por terciaria/universitaria (13,301) y primaria (6,851). Este perfil educativo sugiere que la mayoría de los clientes tienen al menos educación media completa, lo que podría facilitar la comprensión de productos financieros más complejos. La presencia de un grupo con educación desconocida (unknown, 1,857) podría representar oportunidades para mejorar la recolección de datos o indicar clientes con menor engagement bancario

DEFAULT

La abrumadora mayoría no presenta incumplimientos (44,396 vs. 815 con default=yes). Esta distribución extremadamente sesgada sugiere que la base contiene principalmente clientes con buen historial crediticio, o que los clientes con incumplimientos son sistemáticamente excluidos de las campañas de marketing. La variable podría tener poco poder predictivo debido a este desbalance

HOUSING

La distribución es relativamente equilibrada (20,081 sin crédito vs. 25,130 con crédito hipotecario). Esto indica que aproximadamente el 55.6% de los clientes tienen préstamos para vivienda, lo que podría relacionarse con su capacidad de ahorro y propensión a otros productos financieros. Los clientes sin hipoteca podrían representar tanto a jóvenes como a personas con mayor capacidad de ahorro.

LOAN

La mayoría no tiene préstamos personales (37,967 vs. 7,244 con préstamos). Esta proporción (84% sin préstamos) sugiere que los préstamos personales no son un producto masivo en esta cartera, o que los clientes con préstamos podrían estar menos dispuestos a contratar depósitos a plazo debido a sus obligaciones de deuda existentes.

CONTACT

El contacto celular (cellular, 29,285) domina claramente sobre el telefónico fijo (telephone, 2,906) y los casos desconocidos (unknown, 13,020). Esta distribución refleja la preferencia actual por la comunicación móvil y sugiere que las campañas podrían optimizarse para este canal. Los contactos desconocidos representan un reto para el análisis y podrían indicar registros incompletos.

MONTH

Mayo (may, 13,766) destaca como el mes con mayor actividad de campaña, seguido por julio (jul, 6,895) y agosto (aug, 6,247). Los meses con menor actividad son diciembre (dec, 214) y marzo (mar, 477). Esta distribución podría reflejar estrategias de marketing estacionales, evitando periodos festivos (diciembre) o coincidiendo con momentos de bonificación (mayo-julio). La variación mensual debería considerarse al analizar los resultados de la campaña.

POUTCOME

Predominan los casos sin información previa (unknown, 36,959), lo que limita el análisis del historial. Entre los resultados conocidos, los fracasos (failure, 4,901) superan a los éxitos (success, 1,511) y otros resultados (other, 1,840). Esto sugiere que, cuando hay historial disponible, las campañas anteriores tuvieron más resultados negativos que positivos, lo que podría afectar la efectividad de los contactos actuales.

Y

El marcado desbalanceo (39,922 no vs. 5,289 sí) indica que solo el 11.7% de los clientes contactados suscribieron el depósito. Esta proporción plantea desafíos para el modelado predictivo, ya que los algoritmos podrían tender a favorecer la clase mayoritaria. Las estrategias de muestreo o ponderación podrían ser necesarias para mejorar la predicción de la clase minoritaria (suscritores).

DEFINICIÓN DE VARIABLES PREDICTORAS (X) Y VARIABLE OBJETIVO (Y)

Las variables X son como la edad del cliente (age), su tipo de trabajo (job), su estado civil (marital), el nivel educativo (education), ¿Tiene deudas impagas en créditos anteriores? (default), el balance promedio anual (balance), si tiene préstamos de vivienda (housing), si tiene un préstamo personal (loan), el tipo de contacto realizado (contact), el día y mes del último contacto (day y month), la duración del último contacto (duration), el número de contactos en la campaña (campaign), los días desde el último contacto (pdays), el número de contactos previos (previous) y el resultado de la campaña anterior (poutcome). Por otro lado, la variable Y es el resultado que se desea predecir, en este caso, si el cliente ha suscrito o no un depósito a plazo (y), que es una variable binaria (“yes” o “no”).

Por lo tanto, nuestro problema estadistico para esta base de datos sera ¿Qué características de los clientes influyen significativamente en la probabilidad de que suscriban un depósito a plazo fijo?

PREPARACIÓN DE LOS DATOS

Se adoptó una estrategia sistemática para seleccionar las variables más relevantes. Inicialmente, se construyó un modelo logístico completo que incorporaba todas las variables disponibles: demográficas (como edad, estado civil y educación), financieras (saldo, préstamos, créditos) y operacionales (duración del contacto, resultado de campañas anteriores, entre otras). Este modelo inicial sirvió como punto de referencia para evaluar los p-valores asociados a cada variable, se identificaron aquellas con un impacto real en la predicción (p < 0.05).

MODELO LOGISTICO COMPLETO (PRUEBA PARA IDENTIFICAR VARIABLES IMPORTANTES)

# Cargar librerías necesarias
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.4.3
## 
## 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)
## Warning: package 'ggplot2' was built under R version 4.4.3
library(readxl)

# Cargar los datos (reemplaza la ruta si es necesario)
Banco_2 <- read_excel("C:/Users/Sanvi/Downloads/Banco 2.xlsx")

# Convertir la variable dependiente 'y' a valores numéricos (0 y 1)
Banco_2$y <- ifelse(Banco_2$y == "yes", 1, 0)

# Convertir las variables categóricas a factores
Banco_2$job <- factor(Banco_2$job, levels = c("admin.", "unknown", "unemployed", "management", "housemaid", "entrepreneur", "student",
                                               "blue-collar", "self-employed", "retired", "technician", "services"))
Banco_2$marital <- factor(Banco_2$marital, levels = c("married", "divorced", "single"))
Banco_2$education <- factor(Banco_2$education, levels = c("unknown", "secondary", "primary", "tertiary"))
Banco_2$default <- factor(Banco_2$default, levels = c("yes", "no"))
Banco_2$housing <- factor(Banco_2$housing, levels = c("yes", "no"))
Banco_2$loan <- factor(Banco_2$loan, levels = c("yes", "no"))
Banco_2$contact <- factor(Banco_2$contact, levels = c("unknown", "telephone", "cellular"))
Banco_2$month <- factor(Banco_2$month, levels = c("jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"))
Banco_2$poutcome <- factor(Banco_2$poutcome, levels = c("unknown", "other", "failure", "success"))

# Crear el modelo de regresión logística
# Vamos a predecir la variable dependiente 'y', que ahora es binaria (0 o 1)
model <- glm(y ~ age + job + marital + education + default + balance + housing + loan + contact + day + month + duration + 
              campaign + pdays + previous + poutcome, 
             data = Banco_2, 
             family = binomial)

# Ver los resultados del modelo
summary(model)
## 
## Call:
## glm(formula = y ~ age + job + marital + education + default + 
##     balance + housing + loan + contact + day + month + duration + 
##     campaign + pdays + previous + poutcome, family = binomial, 
##     data = Banco_2)
## 
## Coefficients:
##                      Estimate Std. Error z value Pr(>|z|)    
## (Intercept)        -6.559e+00  2.645e-01 -24.801  < 2e-16 ***
## age                 1.127e-04  2.205e-03   0.051 0.959233    
## jobunknown         -3.133e-01  2.335e-01  -1.342 0.179656    
## jobunemployed      -1.767e-01  1.116e-01  -1.583 0.113456    
## jobmanagement      -1.653e-01  7.329e-02  -2.255 0.024130 *  
## jobhousemaid       -5.040e-01  1.365e-01  -3.693 0.000221 ***
## jobentrepreneur    -3.571e-01  1.256e-01  -2.844 0.004455 ** 
## jobstudent          3.821e-01  1.090e-01   3.505 0.000457 ***
## jobblue-collar     -3.099e-01  7.267e-02  -4.264 2.01e-05 ***
## jobself-employed   -2.983e-01  1.120e-01  -2.664 0.007726 ** 
## jobretired          2.524e-01  9.722e-02   2.596 0.009436 ** 
## jobtechnician      -1.760e-01  6.893e-02  -2.554 0.010664 *  
## jobservices        -2.238e-01  8.406e-02  -2.662 0.007763 ** 
## maritaldivorced     1.795e-01  5.891e-02   3.046 0.002318 ** 
## maritalsingle       2.720e-01  4.594e-02   5.919 3.23e-09 ***
## educationsecondary -6.695e-02  9.124e-02  -0.734 0.463085    
## educationprimary   -2.505e-01  1.039e-01  -2.411 0.015915 *  
## educationtertiary   1.285e-01  9.586e-02   1.340 0.180204    
## defaultno           1.668e-02  1.628e-01   0.102 0.918407    
## balance             1.283e-05  5.148e-06   2.493 0.012651 *  
## housingno           6.754e-01  4.387e-02  15.395  < 2e-16 ***
## loanno              4.254e-01  5.999e-02   7.091 1.33e-12 ***
## contacttelephone    1.460e+00  1.006e-01  14.508  < 2e-16 ***
## contactcellular     1.623e+00  7.317e-02  22.184  < 2e-16 ***
## day                 9.969e-03  2.497e-03   3.993 6.53e-05 ***
## monthfeb            1.114e+00  1.321e-01   8.435  < 2e-16 ***
## monthmar            2.852e+00  1.522e-01  18.735  < 2e-16 ***
## monthapr            1.262e+00  1.217e-01  10.367  < 2e-16 ***
## monthmay            8.626e-01  1.210e-01   7.131 9.96e-13 ***
## monthjun            1.715e+00  1.342e-01  12.781  < 2e-16 ***
## monthjul            4.309e-01  1.198e-01   3.597 0.000322 ***
## monthaug            5.678e-01  1.211e-01   4.688 2.76e-06 ***
## monthsep            2.136e+00  1.522e-01  14.034  < 2e-16 ***
## monthoct            2.143e+00  1.411e-01  15.193  < 2e-16 ***
## monthnov            3.883e-01  1.246e-01   3.115 0.001836 ** 
## monthdec            1.953e+00  1.995e-01   9.788  < 2e-16 ***
## duration            4.194e-03  6.453e-05  64.986  < 2e-16 ***
## campaign           -9.078e-02  1.014e-02  -8.955  < 2e-16 ***
## pdays              -1.027e-04  3.061e-04  -0.335 0.737268    
## previous            1.015e-02  6.503e-03   1.561 0.118476    
## poutcomeother       2.953e-01  1.068e-01   2.766 0.005677 ** 
## poutcomefailure     9.179e-02  9.347e-02   0.982 0.326093    
## poutcomesuccess     2.383e+00  8.625e-02  27.627  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 32631  on 45210  degrees of freedom
## Residual deviance: 21562  on 45168  degrees of freedom
## AIC: 21648
## 
## Number of Fisher Scoring iterations: 6
# Hacer predicciones con el modelo
predicciones <- predict(model, type = "response")
predicciones_class <- ifelse(predicciones > 0.5, 1, 0)

# Evaluar el desempeño del modelo
table(Predicted = predicciones_class, Actual = Banco_2$y)
##          Actual
## Predicted     0     1
##         0 38940  3456
##         1   982  1833

Se desarrolló un modelo de regresión logística para identificar los factores determinantes en la suscripción de depósitos a plazo (variable ‘y’). El modelo incorporó variables demográficas (edad, estado civil), financieras (saldo, créditos), operacionales (duración de contacto, medio de contacto) e históricas (resultados de campañas anteriores). Los resultados mostraron que la duración del contacto (duration) tuvo el efecto más significativo (p < 0.001), donde llamadas más largas aumentaron considerablemente la probabilidad de suscripción. Variables como el tipo de contacto (cellular/telephone vs unknown) y meses específicos (marzo, octubre) también mostraron fuerte significancia estadística. El modelo presentó una exactitud global del 90.19%, aunque con cierta tendencia a subestimar los casos positivos debido al desbalanceo natural de los datos (11.7% de suscripciones). Los coeficientes sugieren que clientes jubilados, con mayor saldo y sin préstamos personales tienen mayor propensión a suscribir, mientras que múltiples contactos (campaign) reducen la probabilidad de éxito. Este análisis proporciona insights valiosos para optimizar las estrategias de marketing, focalizando esfuerzos en los segmentos y momentos identificados como más efectivos.

Finalmente, se seleccionaron como variables independientes aquellas que se consideran relevantes para el comportamiento del cliente frente a la campaña. Estas incluyen: duration (duración de la última llamada), campaign (número de contactos realizados durante la campaña), contact (medio de contacto utilizado), balance (saldo promedio anual en la cuenta), loan (si tiene un préstamo personal), housing (si tiene un préstamo hipotecario), job (ocupación), marital (estado civil), month (mes de contacto) y poutcome (resultado de campañas anteriores).

MODELADO

Se desarrolló un modelo de regresión logística , seleccionando únicamente las variables con mayor impacto estadístico para predecir la suscripción a depósitos a plazo (variable ‘y’)

# Cargar librerías necesarias
library(dplyr)
library(ggplot2)
library(readxl)

# Cargar los datos
Banco_2 <- read_excel("C:/Users/Sanvi/Downloads/Banco 2.xlsx")

# Convertir la variable dependiente 'y' a binaria (0 = no, 1 = yes)
Banco_2$y <- ifelse(tolower(trimws(Banco_2$y)) == "yes", 1, 0)

# Convertir variables categóricas a factores con niveles definidos
Banco_2$job <- factor(Banco_2$job, levels = c("admin.", "unknown", "unemployed", "management", "housemaid", "entrepreneur", "student",
                                               "blue-collar", "self-employed", "retired", "technician", "services"))
Banco_2$marital <- factor(Banco_2$marital, levels = c("married", "divorced", "single"))
Banco_2$education <- factor(Banco_2$education, levels = c("unknown", "secondary", "primary", "tertiary"))
Banco_2$housing <- factor(Banco_2$housing, levels = c("yes", "no"))
Banco_2$loan <- factor(Banco_2$loan, levels = c("yes", "no"))
Banco_2$contact <- factor(Banco_2$contact, levels = c("unknown", "telephone", "cellular"))
Banco_2$month <- factor(Banco_2$month, levels = c("jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"))
Banco_2$poutcome <- factor(Banco_2$poutcome, levels = c("unknown", "other", "failure", "success"))

# Eliminar filas con NA (si las hay, por seguridad)
Banco_2 <- na.omit(Banco_2)

# Crear el nuevo modelo logístico con variables seleccionadas
modelo_opt <- glm(y ~ balance + day + duration + campaign + 
                    job + marital + education + housing + loan + 
                    contact + month + poutcome,
                  data = Banco_2,
                  family = binomial)

# Ver el resumen del modelo
summary(modelo_opt)
## 
## Call:
## glm(formula = y ~ balance + day + duration + campaign + job + 
##     marital + education + housing + loan + contact + month + 
##     poutcome, family = binomial, data = Banco_2)
## 
## Coefficients:
##                      Estimate Std. Error z value Pr(>|z|)    
## (Intercept)        -6.534e+00  1.907e-01 -34.260  < 2e-16 ***
## balance             1.289e-05  5.127e-06   2.515 0.011903 *  
## day                 9.898e-03  2.496e-03   3.965 7.33e-05 ***
## duration            4.194e-03  6.453e-05  64.988  < 2e-16 ***
## campaign           -9.037e-02  1.013e-02  -8.925  < 2e-16 ***
## jobunknown         -3.122e-01  2.331e-01  -1.339 0.180441    
## jobunemployed      -1.779e-01  1.116e-01  -1.594 0.111000    
## jobmanagement      -1.646e-01  7.323e-02  -2.248 0.024567 *  
## jobhousemaid       -5.043e-01  1.360e-01  -3.707 0.000210 ***
## jobentrepreneur    -3.586e-01  1.254e-01  -2.860 0.004241 ** 
## jobstudent          3.822e-01  1.070e-01   3.571 0.000356 ***
## jobblue-collar     -3.116e-01  7.261e-02  -4.292 1.77e-05 ***
## jobself-employed   -2.983e-01  1.120e-01  -2.664 0.007720 ** 
## jobretired          2.541e-01  8.738e-02   2.907 0.003644 ** 
## jobtechnician      -1.760e-01  6.892e-02  -2.554 0.010661 *  
## jobservices        -2.252e-01  8.404e-02  -2.680 0.007359 ** 
## maritaldivorced     1.785e-01  5.865e-02   3.043 0.002339 ** 
## maritalsingle       2.704e-01  4.225e-02   6.400 1.56e-10 ***
## educationsecondary -6.705e-02  9.093e-02  -0.737 0.460895    
## educationprimary   -2.493e-01  1.039e-01  -2.399 0.016423 *  
## educationtertiary   1.291e-01  9.530e-02   1.354 0.175597    
## housingno           6.755e-01  4.350e-02  15.529  < 2e-16 ***
## loanno              4.254e-01  5.986e-02   7.108 1.18e-12 ***
## contacttelephone    1.461e+00  1.001e-01  14.593  < 2e-16 ***
## contactcellular     1.622e+00  7.310e-02  22.189  < 2e-16 ***
## monthfeb            1.115e+00  1.321e-01   8.434  < 2e-16 ***
## monthmar            2.850e+00  1.522e-01  18.727  < 2e-16 ***
## monthapr            1.258e+00  1.217e-01  10.339  < 2e-16 ***
## monthmay            8.587e-01  1.208e-01   7.107 1.18e-12 ***
## monthjun            1.714e+00  1.342e-01  12.766  < 2e-16 ***
## monthjul            4.290e-01  1.198e-01   3.581 0.000342 ***
## monthaug            5.664e-01  1.211e-01   4.677 2.91e-06 ***
## monthsep            2.134e+00  1.521e-01  14.029  < 2e-16 ***
## monthoct            2.144e+00  1.410e-01  15.201  < 2e-16 ***
## monthnov            3.885e-01  1.246e-01   3.118 0.001818 ** 
## monthdec            1.952e+00  1.995e-01   9.783  < 2e-16 ***
## poutcomeother       3.139e-01  7.927e-02   3.960 7.49e-05 ***
## poutcomefailure     9.765e-02  5.747e-02   1.699 0.089284 .  
## poutcomesuccess     2.397e+00  6.669e-02  35.947  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 32631  on 45210  degrees of freedom
## Residual deviance: 21565  on 45172  degrees of freedom
## AIC: 21643
## 
## Number of Fisher Scoring iterations: 6
# Hacer predicciones
pred_opt <- predict(modelo_opt, type = "response")
pred_class_opt <- ifelse(pred_opt > 0.5, 1, 0)

# Matriz de confusión
conf_mat <- table(Predicho = pred_class_opt, Real = Banco_2$y)
print("Matriz de confusión:")
## [1] "Matriz de confusión:"
print(conf_mat)
##         Real
## Predicho     0     1
##        0 38942  3453
##        1   980  1836
# Calcular exactitud del modelo
accuracy <- sum(diag(conf_mat)) / sum(conf_mat)
cat("Exactitud del modelo:", round(accuracy, 4), "\n")
## Exactitud del modelo: 0.9019

INTERPRETACION DEL MODELO LOGISTICO

Duración del Contacto (duration)

El tiempo de interacción con el cliente es el factor más determinante. Por cada segundo adicional de duración en la llamada, la probabilidad de suscripción aumenta significativamente (coeficiente +0.0042, p < 0.001). Esto sugiere que las conversaciones más extensas permiten una mejor identificación de necesidades y oferta personalizada.

Resultado de Campañas Anteriores (poutcome)

Los clientes que anteriormente suscribieron productos (poutcome = success) muestran una probabilidad extraordinariamente más alta de volver a hacerlo (coeficiente +2.40). Esto equivale a aproximadamente 11 veces más probabilidades (e^2.40) comparado con otros clientes. Este hallazgo refuerza la importancia de segmentar las bases de datos para priorizar a quienes ya han respondido positivamente a ofertas previas, ya que representan leads de mayor calidad.

Tipo de Contacto (contact)

El canal de comunicación marca una diferencia crucial. Los contactos realizados mediante celular (coeficiente +1.62) o teléfono fijo (+1.46) son significativamente más efectivos que los contactos genéricos (“unknown”). Esto probablemente refleja la mayor capacidad de estos canales para establecer una conexión personalizada e inmediata con el cliente. Las estrategias de marketing deberían priorizar estos canales directos sobre métodos impersonales como correos masivos.

Número de Intentos de Contacto (campaign)

Cada intento adicional de contacto reduce la probabilidad de éxito (coeficiente -0.09). Esto indica un claro efecto de saturación o molestia cuando los clientes son contactados repetidamente. Se recomienda limitar los intentos a un máximo de 2-3 por campaña y desarrollar estrategias de contactos más inteligentes y espaciados en el tiempo para evitar el rechazo.

Situación Crediticia (housing y loan)

Los clientes sin deudas hipotecarias (housing = no) muestran una mayor disposición a contratar depósitos (coeficiente +0.68), al igual que aquellos sin préstamos personales (loan = no, coeficiente +0.43). Esto sugiere que la capacidad financiera disponible es un factor clave. Los equipos comerciales podrían utilizar estos indicadores para priorizar clientes con mayor liquidez y capacidad de ahorro.

Perfil Ocupacional (job)

Estudiantes (coeficiente +0.38) y jubilados (+0.25) presentan mayor propensión a suscribir, posiblemente por necesidades específicas de planificación financiera. En contraste, trabajadores manuales (blue-collar, housemaid) muestran menor interés. Esta información permite afinar los mensajes comerciales según el perfil profesional del cliente.

Estado Civil (marital)

Los clientes solteros (coeficiente +0.27) y divorciados (+0.18) muestran mayor probabilidad de suscripción que los casados. Esto podría relacionarse con diferentes prioridades financieras o mayor flexibilidad en la toma de decisiones. Las campañas podrían adaptar su enfoque según este perfil demográfico.

Temporalidad (month)

Los meses de marzo (coeficiente +2.85), octubre (+2.14) y diciembre (+1.95) presentan especial efectividad, probablemente asociados a ciclos económicos como pagos de bonos o cierres fiscales. Este patrón temporal sugiere la conveniencia de intensificar esfuerzos comerciales durante estos períodos clave.

Saldo Bancario (balance)

Aunque con un efecto modesto (coeficiente +1.29e-05), los clientes con mayores saldos muestran mayor propensión. Esto refuerza la estrategia de priorizar clientes con mayor capacidad económica, aunque debe combinarse con otros factores para una segmentación efectiva

Los p-valores en este análisis de regresión logística nos indican la significancia estadística de cada variable predictora

Variables Altamente Significativas (p < 0.001)

Estas variables tienen un impacto extremadamente confiable en la predicción:

Duration (p < 2e-16): La duración del contacto es el factor más importante.

Contactcellular (p < 2e-16): Los contactos por celular son significativamente más efectivos.

Poutcomesuccess (p < 2e-16): El éxito previo en campañas es el predictor más fuerte.

Monthmar (p < 2e-16): Marzo muestra un efecto estacional muy marcado.

Variables Muy Significativas (p < 0.01)

Campaign (p < 2e-16): Cada contacto adicional reduce claramente la probabilidad.

Housingno (p < 2e-16): No tener crédito hipotecario aumenta notablemente la propensión.

Maritalsingle (p = 1.56e-10): Los solteros muestran mayor probabilidad que otros estados civiles.

Variables Significativas (p < 0.05)

balance (p = 0.012): El saldo tiene un efecto pequeño pero significativo.

jobblue-collar (p = 1.77e-05): Los trabajadores manuales tienen menor propensión.

educationprimary (p = 0.016): Educación primaria vs. secundaria muestra diferencia.

Variables Marginalmente Significativas (0.05 < p < 0.1)

poutcomefailure (p = 0.089): Los fracasos previos podrían tener cierto efecto negativo.

Variables No Significativas (p > 0.1)

Estas variables no aportan evidencia suficiente de su impacto:

jobunknown (p = 0.180)

jobunemployed (p = 0.111)

educationsecondary (p = 0.461)

educationtertiary (p = 0.176)

IMPORTANCIA BASADA EN LOS P-VALORES

Variables con p < 0.001: Factores críticos que deben ser el foco principal.

Variables con 0.001 < p < 0.05: Predictores importantes a considerar.

Variables con p > 0.05: Podrían eliminarse para simplificar el modelo sin perder poder predictivo.

Los p-valores en este análisis revelan qué variables tienen un impacto estadísticamente significativo en la probabilidad de que un cliente suscriba un depósito a plazo. Las variables con p-valores extremadamente bajos (p < 0.001), como duration, contactcellular y poutcomesuccess, emergen como los predictores más confiables y potentes, demostrando una relación altamente significativa con el resultado. Variables con p-valores entre 0.001 y 0.05, como balance, campaign y varias categorías de job, también muestran influencia significativa, aunque con menor fuerza relativa. Por otro lado, variables como educationsecondary y jobunknown (p > 0.05) no aportan evidencia suficiente para considerarse relevantes en el modelo actual.

Esta jerarquía de significancia estadística permite priorizar acciones comerciales: enfocarse en los factores más impactantes (como maximizar la duración de contactos de calidad o capitalizar el historial previo de éxito) mientras se descartan variables redundantes. Los p-valores, así, no solo validan la solidez del modelo, sino que también guían decisiones estratégicas basadas en evidencia cuantitativa. En esencia, el modelo confirma que la efectividad de las campañas depende críticamente de cómo y a quién se contacta, más que de características demográficas genéricas.

EVALUACIÓN

# Predicciones (probabilidades)
pred_opt <- predict(modelo_opt, type = "response")

# Clasificación binaria: 1 si probabilidad > 0.5, si no 0
pred_class_opt <- ifelse(pred_opt > 0.5, 1, 0)

# Matriz de confusión
matriz_conf <- table(Predicho = pred_class_opt, Real = Banco_2$y)
print("Matriz de confusión:")
## [1] "Matriz de confusión:"
print(matriz_conf)
##         Real
## Predicho     0     1
##        0 38942  3453
##        1   980  1836
# Cálculo de exactitud (accuracy)
exactitud <- mean(pred_class_opt == Banco_2$y)
print(paste("Exactitud del modelo:", round(exactitud, 4)))
## [1] "Exactitud del modelo: 0.9019"

La matriz de confusión es una herramienta que permite evaluar el desempeño de un modelo de clasificación comparando las predicciones realizadas con los valores reales. En este caso, el objetivo del modelo es predecir si un cliente suscribirá un depósito a plazo como parte de una campaña de marketing telefónico llevada a cabo por una entidad bancaria portuguesa.

En la matriz presentada, las filas corresponden a las predicciones del modelo y las columnas a los valores reales:

El modelo predijo correctamente que 38,942 clientes no suscribieron el depósito (predicción 0, valor real 0).

También acertó al predecir que 1,836 clientes sí lo suscribieron (predicción 1, valor real 1).

Sin embargo, cometió algunos errores: clasificó erróneamente a 3,453 clientes como no suscriptores, cuando en realidad sí lo eran (falsos negativos). Asimismo, predijo como suscriptores a 980 clientes que en realidad no lo fueron (falsos positivos).

A partir de esta información, se calculó la exactitud del modelo, que corresponde al porcentaje de predicciones correctas respecto al total de casos. En este análisis, el modelo alcanzó una exactitud del 90,19%, lo que indica un buen nivel de desempeño general. Sin embargo, también es importante considerar los errores cometidos, especialmente los falsos negativos, ya que representan posibles oportunidades perdidas para la campaña.

DESPLIEGUE

Se ha desarrollado una aplicación interactiva que permite a los usuarios ingresar datos clave de los clientes y obtener, en tiempo real, una predicción sobre la probabilidad de que estos suscriban un depósito a plazo. Esta herramienta utiliza un modelo logístico ajustado con las variables más significativas, identificadas mediante un riguroso análisis estadístico, lo que garantiza resultados precisos y accionables para los equipos comerciales y de marketing. La aplicación se ha construido siguiendo la metodología CRISP-DM (Cross Industry Standard Process for Data Mining), un estándar ampliamente reconocido en proyectos de ciencia de datos que consta de seis fases principales: comprensión del negocio, comprensión de los datos, preparación de los datos, modelado, evaluación y despliegue. Este enfoque estructurado asegura que la solución no solo sea robusta y escalable, sino también adaptable a cambios en los datos o en las necesidades del negocio. Entre los principales beneficios de la aplicación destacan su alta precisión, respaldada por métricas validadas como una exactitud del 90.19%, y su capacidad para adaptarse a nuevos datos mediante actualizaciones periódicas del modelo. Además, la herramienta ofrece transparencia al explicar las predicciones en términos comprensibles, lo que facilita su adopción por parte de los usuarios finales. Al integrar ciencia de datos con usabilidad, esta aplicación se convierte en un activo estratégico para optimizar campañas, priorizar clientes y personalizar interacciones, todo ello con el respaldo de un proceso metodológico sólido y reproducible.

saveRDS(modelo_opt, file = "modelo_logistico_Banco2.rds")
# app.R

library(shiny)
library(readxl)

# Cargar modelo
modelo <- readRDS("modelo_logistico_Banco2.rds")

# Interfaz de usuario
ui <- fluidPage(
  titlePanel("Predicción de aceptación de campaña bancaria"),
  
  sidebarLayout(
    sidebarPanel(
      numericInput("balance", "Balance", value = 0),
      numericInput("day", "Día del mes", value = 15),
      numericInput("duration", "Duración (segundos)", value = 100),
      numericInput("campaign", "Número de contactos durante campaña", value = 1),
      
      selectInput("job", "Trabajo", choices = c("admin.", "blue-collar", "entrepreneur", "housemaid", 
                                                 "management", "retired", "self-employed", 
                                                 "services", "student", "technician", 
                                                 "unemployed", "unknown")),
      
      selectInput("marital", "Estado civil", choices = c("married", "single", "divorced")),
      selectInput("education", "Educación", choices = c("primary", "secondary", "tertiary", "unknown")),
      selectInput("housing", "Crédito hipotecario", choices = c("yes", "no")),
      selectInput("loan", "Préstamo personal", choices = c("yes", "no")),
      selectInput("contact", "Tipo de contacto", choices = c("cellular", "telephone", "unknown")),
      selectInput("month", "Mes del contacto", choices = c("jan", "feb", "mar", "apr", "may", "jun",
                                                           "jul", "aug", "sep", "oct", "nov", "dec")),
      selectInput("poutcome", "Resultado de campaña anterior", choices = c("success", "failure", "other", "unknown")),
      actionButton("predecir", "Predecir")
    ),
    
    mainPanel(
      h3("Resultado de la predicción:"),
      verbatimTextOutput("resultado")
    )
  )
)

# Lógica del servidor
server <- function(input, output) {
  
  observeEvent(input$predecir, {
    
    # Crear un nuevo dataframe con los inputs
    nuevo_dato <- data.frame(
      balance = input$balance,
      day = input$day,
      duration = input$duration,
      campaign = input$campaign,
      job = input$job,
      marital = input$marital,
      education = input$education,
      housing = input$housing,
      loan = input$loan,
      contact = input$contact,
      month = input$month,
      poutcome = input$poutcome
    )
    
    # Predecir probabilidad
    prob <- predict(modelo, newdata = nuevo_dato, type = "response")
    
    # Clasificar
    clase <- ifelse(prob > 0.5, "Acepta (1)", "No acepta (0)")
    
    # Mostrar resultado
    output$resultado <- renderText({
      paste("Probabilidad de aceptar:", round(prob, 4), "\nClasificación:", clase)
    })
  })
}

# Ejecutar la app
shinyApp(ui = ui, server = server)
Shiny applications not supported in static R Markdown documents

CONCLUSIÓN

El análisis desarrollado bajo la metodología CRISP-DM permitió abordar de forma integral un problema de clasificación relacionado con campañas de marketing directo implementadas por una entidad bancaria portuguesa. Utilizando una base de datos rica en información demográfica, financiera y de comportamiento del cliente, se construyó un modelo predictivo capaz de anticipar si un cliente suscribirá un depósito a plazo. La selección adecuada de variables y la evaluación mediante una matriz de confusión mostraron que el modelo alcanzó una exactitud del 90,19%, lo cual refleja un desempeño sólido y útil para la toma de decisiones estratégicas.

Como complemento a este análisis, se diseñó una aplicación interactiva que permite visualizar los resultados del modelo y realizar predicciones de manera sencilla. Esta herramienta ofrece a los usuarios una interfaz amigable para explorar los datos, interpretar los resultados y facilitar la implementación del modelo en contextos reales de negocio. La incorporación de esta app fortalece la utilidad práctica del trabajo, permitiendo que las áreas comerciales o de marketing del banco puedan identificar de forma anticipada a los clientes con mayor probabilidad de conversión y enfocar mejor sus esfuerzos.

En conjunto, este proyecto no solo proporciona un modelo predictivo robusto, sino también una solución tecnológica funcional que apoya la eficiencia y efectividad de futuras campañas de marketing.

INTRODUCCION RENDIMIENTO ESTUDIANTIL EN UN EXAMEN DE INGRESO

En el contexto actual, donde la toma de decisiones basada en datos se ha vuelto fundamental en múltiples sectores, la minería de datos y la ciencia de datos juegan un papel crucial. Para llevar a cabo estos procesos de manera estructurada y eficiente, se ha adoptado ampliamente la metodología CRISP-DM (Cross Industry Standard Process for Data Mining), la cual ofrece un enfoque estándar compuesto por seis fases que guían el desarrollo de proyectos de análisis de datos desde la comprensión del problema hasta la implementación de soluciones.

En este estudio, se aplica dicha metodología a un conjunto de datos que contiene información detallada sobre el desempeño de los candidatos en un examen de admisión común, junto con diversas variables demográficas y académicas. Esta base de datos permite investigar los factores que pueden influir en el éxito en pruebas competitivas, convirtiéndose en una herramienta valiosa tanto para investigadores en el ámbito educativo como para profesionales en ciencia de datos interesados en generar modelos predictivos y obtener conocimientos útiles para mejorar los procesos de selección académica.

COMPRENSION DEL NEGOCIO

Una institución académica desea comprender mejor los factores que influyen en el desempeño de los estudiantes en un examen de admisión común. Actualmente, no cuenta con un sistema predictivo que permita anticipar los resultados o identificar perfiles de estudiantes que puedan requerir apoyo académico adicional.

Problema educativo:

Dificultad para identificar de forma temprana a los estudiantes con mayor o menor probabilidad de éxito en el examen de ingreso, lo cual limita la toma de decisiones basada en datos para mejorar los procesos de orientación, refuerzo académico y selección.

Objetivos

Predecir el nivel de desempeño de un estudiante en el examen de admisión (variable Performance), teniendo en cuenta:

Factores demográficos: género, casta (grupo social), medio de instrucción, ocupación de los padres.

Formación académica: tipo de educación recibida en grados anteriores, asistencia a clases de refuerzo.

Historial académico: porcentaje de calificaciones obtenidas en los grados 10 y 12.

Condiciones del examen: duración del examen, condiciones contextuales.

COMPRENSIÒN DE DATOS

library(readxl)
Rendimiento_2 <- read_excel("Rendimiento_2.xlsx")
head(Rendimiento_2)
## # A tibble: 6 × 12
##   Gender Caste   coaching Class_ten_education twelve_education medium 
##   <chr>  <chr>   <chr>    <chr>               <chr>            <chr>  
## 1 male   General NO       SEBA                AHSEC            ENGLISH
## 2 male   OBC     WA       SEBA                AHSEC            OTHERS 
## 3 male   OBC     OA       OTHERS              CBSE             ENGLISH
## 4 male   General WA       SEBA                AHSEC            OTHERS 
## 5 male   General OA       SEBA                CBSE             ENGLISH
## 6 male   General WA       CBSE                CBSE             ENGLISH
## # ℹ 6 more variables: Class_X_Percentage <chr>, Class_XII_Percentage <chr>,
## #   Father_occupation <chr>, Mother_occupation <chr>, time <chr>,
## #   Performance <chr>

DESCRIPCIÒN DE CADA VARIABLE

Examination Performance: Resultado del estudiante en el examen de admisión.

Sex: Género del candidato.

Caste: Clasificación de casta del candidato.

Coaching Details: Tipo de clases preparatorias asistidas por el candidato.

Board Details: Consejo educativo en los grados X y XII.

Medium of Instruction: Idioma de enseñanza en el grado XII.

Class X Percentage: Calificación porcentual en el grado X.

Class XII Percentage: Calificación porcentual en el grado XII.

Father’s Occupation / Mother’s Occupation: Profesión de los padres del candidato

Rendimiento_2 <- read_excel("C:/Users/Sanvi/Downloads/Rendimiento_2.xlsx")
frecuencia_gender <- table(Rendimiento_2$Gender)
cat("Frecuencia de 'Gender':\n")
## Frecuencia de 'Gender':
print(frecuencia_gender)
## 
## female   male 
##    311    355
frecuencia_caste <- table(Rendimiento_2$Caste)
cat("Frecuencia de 'Caste':\n")
## Frecuencia de 'Caste':
print(frecuencia_caste)
## 
## General     OBC      SC      ST 
##     329     162      67     108
frecuencia_coaching <- table(Rendimiento_2$coaching)
cat("Frecuencia de 'Coaching':\n")
## Frecuencia de 'Coaching':
print(frecuencia_coaching)
## 
##  NO  OA  WA 
## 150  67 449
frecuencia_class10 <- table(Rendimiento_2$Class_ten_education)
cat("Frecuencia de 'Class_ten_education':\n")
## Frecuencia de 'Class_ten_education':
print(frecuencia_class10)
## 
##   CBSE OTHERS   SEBA 
##    249     21    396
frecuencia_class12 <- table(Rendimiento_2$twelve_education)
cat("Frecuencia de 'twelve_education':\n")
## Frecuencia de 'twelve_education':
print(frecuencia_class12)
## 
##  AHSEC   CBSE OTHERS 
##    368    290      8
frecuencia_medium <- table(Rendimiento_2$medium)
cat("Frecuencia de 'medium':\n")
## Frecuencia de 'medium':
print(frecuencia_medium)
## 
## ASSAMESE  ENGLISH   OTHERS 
##       56      536       74
frecuencia_x <- table(Rendimiento_2$Class_X_Percentage)
cat("Frecuencia de 'Class_X_Percentage':\n")
## Frecuencia de 'Class_X_Percentage':
print(frecuencia_x)
## 
##   Average Excellent      Good        Vg 
##        13       511        41       101
frecuencia_xii <- table(Rendimiento_2$Class_XII_Percentage)
cat("Frecuencia de 'Class_XII_Percentage':\n")
## Frecuencia de 'Class_XII_Percentage':
print(frecuencia_xii)
## 
##   Average Excellent      Good        Vg 
##        12       398        75       181
frecuencia_father <- table(Rendimiento_2$Father_occupation)
cat("Frecuencia de 'Father_occupation':\n")
## Frecuencia de 'Father_occupation':
print(frecuencia_father)
## 
##   BANK_OFFICIAL        BUSINESS COLLEGE_TEACHER      CULTIVATOR          DOCTOR 
##              23             103              27              27              55 
##        ENGINEER          OTHERS  SCHOOL_TEACHER 
##              45             277             109
frecuencia_mother <- table(Rendimiento_2$Mother_occupation)
cat("Frecuencia de 'Mother_occupation':\n")
## Frecuencia de 'Mother_occupation':
print(frecuencia_mother)
## 
##   BANK_OFFICIAL        BUSINESS COLLEGE_TEACHER      CULTIVATOR          DOCTOR 
##               4               3              20               1              13 
##        ENGINEER      HOUSE_WIFE          OTHERS  SCHOOL_TEACHER 
##               3             442              72             108
frecuencia_time <- table(Rendimiento_2$time)
cat("Frecuencia de 'time':\n")
## Frecuencia de 'time':
print(frecuencia_time)
## 
##  FIVE  FOUR   ONE SEVEN THREE   TWO 
##     1    11   199     1    86   368
frecuencia_perf <- table(Rendimiento_2$Performance)
cat("Frecuencia de 'Performance':\n")
## Frecuencia de 'Performance':
print(frecuencia_perf)
## 
##   Average Excellent      Good        Vg 
##       157       101       210       198

INTERPRETACIÒN DE CADA VARIABLE

Género (Gender):

Hay una ligera mayoría de estudiantes varones (355) en comparación con las mujeres (311). Esto indica una participación equilibrada por género, sin una predominancia marcada.

Casta (Caste):

La mayoría de los estudiantes pertenecen a la casta “General” (329), seguida por OBC (162), ST (108) y SC (67). Esta distribución puede ser útil para analizar si la casta tiene alguna influencia sobre el rendimiento académico o el acceso a recursos.

Asistencia a clases de refuerzo (Coaching):

La mayoría de los estudiantes asistieron a clases de refuerzo de tipo “WA” (449), mientras que 150 no asistieron (“NO”) y 67 asistieron a “OA”. Esto indica que la gran mayoría tuvo algún tipo de apoyo académico externo.

Educación en décimo grado (Class_ten_education):

Los programas de educación “SEBA” (396) y “CBSE” (249) son los más comunes, mientras que “OTHERS” es minoritario (21). SEBA parece ser el sistema educativo predominante en décimo grado.

Educación en duodécimo grado (twelve_education):

La mayoría de los estudiantes provienen de AHSEC (368) y CBSE (290), mientras que muy pocos (8) cursaron estudios bajo otros sistemas (“OTHERS”). Esto refleja que AHSEC y CBSE dominan la educación en este nivel

Idioma de instrucción (medium):

El inglés es el medio de instrucción más utilizado (536 estudiantes), muy por encima del asamés (56) y otras lenguas (74). Esto puede ser relevante para evaluar el impacto del idioma sobre el rendimiento.

Porcentaje de calificaciones en décimo grado (Class_X_Percentage):

La mayoría de los estudiantes obtuvo un rendimiento “Excellent” (511), seguido por “Vg” (101), “Good” (41) y “Average” (13). Esto muestra un desempeño académico alto en décimo grado.

Porcentaje de calificaciones en duodécimo grado (Class_XII_Percentage):

Similar al nivel anterior, la mayoría de estudiantes alcanzó un rendimiento “Excellent” (398), seguido por “Vg” (181), “Good” (75) y “Average” (12). Se observa una continuidad en los altos niveles de desempeño académico.

Ocupación del padre (Father_occupation):

La ocupación más común entre los padres es “OTHERS” (277), lo cual abarca múltiples profesiones no especificadas. Luego vienen “BUSINESS” (103) y “SCHOOL_TEACHER” (109), seguidos por profesiones como doctor, ingeniero, etc.

Ocupación de la madre (Mother_occupation):

La gran mayoría de las madres son “HOUSE_WIFE” (442), seguido por “SCHOOL_TEACHER” (108) y “OTHERS” (72). Las ocupaciones profesionales son mucho menos frecuentes entre las madres.

Tiempo del examen (time):

La mayoría de los estudiantes tomaron el examen en “TWO” (368) y “ONE” (199), indicando que estas son las franjas horarias más comunes. Las demás categorías (como “FIVE”, “SEVEN”) tienen frecuencias muy bajas.

Desempeño general (Performance):

La categoría más numerosa es “Good” (210), seguida muy de cerca por “Vg” (198), “Excellent” (101) y finalmente “Average” (157). Aunque hay una buena proporción de estudiantes con desempeño sobresaliente, también hay una presencia significativa de estudiantes con rendimiento promedio o bajo.

DEFINICIÓN DE VARIABLES PREDICTORAS (X) Y VARIABLE OBJETIVO (Y)

En este conjunto de datos, la variable dependiente (Y) es Examination Performance, ya que representa el resultado del examen que se desea predecir. Las variables independientes (X), que pueden influir en ese resultado, incluyen el género, casta, tipo de preparación, consejo educativo, idioma de enseñanza, calificaciones en grados X y XII, y la ocupación de los padres. Estas variables permiten analizar cómo factores académicos y socioeconómicos afectan el desempeño en exámenes de admisión.

Por lo que, nuestro problema estadistico para esta base de datos sera ¿Qué factores personales, educativos y familiares influyen significativamente en el rendimiento de los estudiantes en el examen de ingreso universitario?

PREPARACIÓN DE LOS DATOS

Se adoptó una estrategia sistemática para seleccionar las variables más relevantes en la predicción del rendimiento estudiantil. Inicialmente, se construyó un modelo de regresión logística binaria que incorporó todas las variables disponibles en la base de datos: características personales (como género, casta, tipo de educación en los grados 10 y 12, idioma de instrucción), académicas (porcentajes de calificaciones obtenidas en los grados 10 y 12), socioeconómicas (ocupación de los padres) y logísticas (tiempo en que se presentó el examen, asistencia a clases de refuerzo).

Este modelo completo sirvió como punto de partida para evaluar la significancia estadística de cada predictor. Se examinaron los valores p asociados a cada variable, identificando aquellas con un impacto significativo en la probabilidad de tener un buen desempeño académico (p < 0.05).

MODELO LOGISTICO COMPLETO (PRUEBA PARA IDENTIFICAR VARIABLES IMPORTANTES)

# Cargar librerías necesarias
library(readxl)
library(dplyr)
library(MASS)       # Para polr
## Warning: package 'MASS' was built under R version 4.4.3
## 
## Adjuntando el paquete: 'MASS'
## The following object is masked from 'package:dplyr':
## 
##     select
library(caret)      # Para matriz de confusión
## Cargando paquete requerido: lattice
# Paso 1: Cargar los datos
Rendimiento_2 <- read_excel("C:/Users/Sanvi/Downloads/Rendimiento_2.xlsx")

# Paso 2: Convertir la variable dependiente Performance a factor ordenado
Rendimiento_2$Performance <- factor(Rendimiento_2$Performance,
                                    levels = c("Average", "Good", "Vg", "Excellent"),
                                    ordered = TRUE)

# Paso 3: Convertir otras variables categóricas a factores
Rendimiento_2 <- Rendimiento_2 %>%
  mutate(across(c(Gender, Caste, coaching, Class_ten_education, twelve_education, medium,
                  Class_X_Percentage, Class_XII_Percentage, Father_occupation, Mother_occupation, time),
                as.factor))

# Paso 4: Ajustar el modelo de regresión logística ordinal
modelo <- polr(Performance ~ Gender + Caste + coaching + Class_ten_education + twelve_education +
                 medium + Class_X_Percentage + Class_XII_Percentage + Father_occupation +
                 Mother_occupation + time,
               data = Rendimiento_2, Hess = TRUE)

# Ver resumen del modelo
summary(modelo)
## Call:
## polr(formula = Performance ~ Gender + Caste + coaching + Class_ten_education + 
##     twelve_education + medium + Class_X_Percentage + Class_XII_Percentage + 
##     Father_occupation + Mother_occupation + time, data = Rendimiento_2, 
##     Hess = TRUE)
## 
## Coefficients:
##                                     Value Std. Error  t value
## Gendermale                        0.22322     0.1708   1.3069
## CasteOBC                         -1.09292     0.2019  -5.4142
## CasteSC                          -2.67490     0.3036  -8.8118
## CasteST                          -5.93332     0.4720 -12.5717
## coachingOA                        1.19048     0.3449   3.4521
## coachingWA                        0.20855     0.2182   0.9557
## Class_ten_educationOTHERS         0.85440     0.5517   1.5487
## Class_ten_educationSEBA          -0.50584     0.2972  -1.7020
## twelve_educationCBSE             -0.63353     0.2971  -2.1320
## twelve_educationOTHERS           -0.56079     1.0152  -0.5524
## mediumENGLISH                     0.70443     0.3354   2.1004
## mediumOTHERS                      1.04288     0.3868   2.6961
## Class_X_PercentageExcellent      -0.82855     0.8922  -0.9287
## Class_X_PercentageGood           -0.58421     0.8969  -0.6513
## Class_X_PercentageVg             -1.18681     0.8982  -1.3214
## Class_XII_PercentageExcellent    -0.46363     0.9788  -0.4737
## Class_XII_PercentageGood         -1.12443     0.9408  -1.1952
## Class_XII_PercentageVg           -1.11523     0.9608  -1.1607
## Father_occupationBUSINESS        -0.94596     0.5091  -1.8581
## Father_occupationCOLLEGE_TEACHER  0.22238     0.6029   0.3689
## Father_occupationCULTIVATOR      -1.36075     0.6934  -1.9623
## Father_occupationDOCTOR          -1.08787     0.5641  -1.9285
## Father_occupationENGINEER        -0.19697     0.5670  -0.3474
## Father_occupationOTHERS          -0.83945     0.4823  -1.7404
## Father_occupationSCHOOL_TEACHER  -1.20340     0.5204  -2.3123
## Mother_occupationBUSINESS        -0.73357     1.5207  -0.4824
## Mother_occupationCOLLEGE_TEACHER  0.09273     1.1406   0.0813
## Mother_occupationCULTIVATOR       0.97063     2.0070   0.4836
## Mother_occupationDOCTOR          -0.42997     1.2173  -0.3532
## Mother_occupationENGINEER        -1.47427     1.4225  -1.0364
## Mother_occupationHOUSE_WIFE      -1.15382     1.0512  -1.0976
## Mother_occupationOTHERS          -1.29713     1.0783  -1.2030
## Mother_occupationSCHOOL_TEACHER  -1.20112     1.0736  -1.1188
## timeFOUR                          1.24080     2.0678   0.6001
## timeONE                           1.46363     2.0144   0.7266
## timeSEVEN                         1.48465     2.6786   0.5543
## timeTHREE                         1.88038     2.0074   0.9367
## timeTWO                           1.87198     2.0161   0.9285
## 
## Intercepts:
##              Value    Std. Error t value 
## Average|Good  -4.5936   2.2946    -2.0019
## Good|Vg       -1.9533   2.2903    -0.8528
## Vg|Excellent   0.0830   2.2878     0.0363
## 
## Residual Deviance: 1279.013 
## AIC: 1361.013
# Paso 5: Hacer predicciones
predicciones <- predict(modelo, newdata = Rendimiento_2)

# Paso 6: Matriz de confusión
confusionMatrix(data = predicciones, reference = Rendimiento_2$Performance)
## Confusion Matrix and Statistics
## 
##            Reference
## Prediction  Average Good  Vg Excellent
##   Average       114    9   4         0
##   Good           42  119  66        20
##   Vg              1   76 109        54
##   Excellent       0    6  19        27
## 
## Overall Statistics
##                                           
##                Accuracy : 0.5541          
##                  95% CI : (0.5154, 0.5922)
##     No Information Rate : 0.3153          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.3799          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: Average Class: Good Class: Vg Class: Excellent
## Sensitivity                  0.7261      0.5667    0.5505          0.26733
## Specificity                  0.9745      0.7193    0.7201          0.95575
## Pos Pred Value               0.8976      0.4818    0.4542          0.51923
## Neg Pred Value               0.9202      0.7828    0.7911          0.87948
## Prevalence                   0.2357      0.3153    0.2973          0.15165
## Detection Rate               0.1712      0.1787    0.1637          0.04054
## Detection Prevalence         0.1907      0.3709    0.3604          0.07808
## Balanced Accuracy            0.8503      0.6430    0.6353          0.61154

Se construyó un modelo de regresión logística ordinal como prueba exploratoria con el objetivo de identificar las variables más relevantes en la predicción del rendimiento académico de los estudiantes. Este modelo incluyó variables demográficas, académicas y familiares. Los resultados muestran que algunas variables tienen asociaciones estadísticamente significativas con el nivel de rendimiento. En particular, pertenecer a una casta distinta a la “General” mostró una fuerte relación negativa con el rendimiento: los coeficientes para las castas OBC (-1.09), SC (-2.67) y ST (-5.93) fueron significativamente negativos (p < 0.05), lo que sugiere que estos estudiantes tienen menor probabilidad de obtener niveles altos de rendimiento.

Asimismo, haber recibido clases de refuerzo únicamente de manera online (coachingOA) se asoció positivamente con un mayor rendimiento (coef. = 1.19, p < 0.01). También se observó un efecto significativo del medio de instrucción: estudiar en inglés (coef. = 0.70) o en un medio catalogado como “Otros” (coef. = 1.04) aumentó la probabilidad de lograr un mejor desempeño.

Finalmente, se seleccionaron las variables más relevantes para explicar el rendimiento académico (Performance) a partir del análisis del modelo logístico ordinal. Las variables retenidas fueron: Caste, coaching, twelve_education, medium y Father_occupation, ya que mostraron una asociación estadísticamente significativa con la variable dependiente y contribuyen a un modelo más sencillo y explicativo.

MODELADO

Se construyó un nuevo modelo logístico ordinal utilizando únicamente las variables que mostraron mayor significancia estadística en el análisis previo. Este modelo reducido incluyó las variables Caste, coaching, twelve_education, medium y Father_occupation, con el objetivo de mejorar la interpretabilidad y la eficiencia predictiva, enfocándose en los factores que realmente impactan el rendimiento académico.

# Cargar librería
library(MASS)

# Ajustar el modelo ordinal con variables significativas
modelo_significativo <- polr(
  Performance ~ Caste + coaching + twelve_education + medium + Father_occupation,
  data = Rendimiento_2,
  Hess = TRUE
)

# Ver resumen del modelo
summary(modelo_significativo)
## Call:
## polr(formula = Performance ~ Caste + coaching + twelve_education + 
##     medium + Father_occupation, data = Rendimiento_2, Hess = TRUE)
## 
## Coefficients:
##                                    Value Std. Error  t value
## CasteOBC                         -1.1755     0.1930  -6.0921
## CasteSC                          -2.6897     0.2974  -9.0438
## CasteST                          -5.9851     0.4488 -13.3344
## coachingOA                        1.2482     0.3215   3.8828
## coachingWA                        0.2530     0.1945   1.3009
## twelve_educationCBSE             -0.1297     0.1824  -0.7111
## twelve_educationOTHERS            0.3242     0.9337   0.3472
## mediumENGLISH                     0.7246     0.3248   2.2307
## mediumOTHERS                      0.9503     0.3686   2.5778
## Father_occupationBUSINESS        -0.9960     0.4825  -2.0645
## Father_occupationCOLLEGE_TEACHER  0.3633     0.5700   0.6374
## Father_occupationCULTIVATOR      -1.0068     0.6513  -1.5460
## Father_occupationDOCTOR          -0.7695     0.5163  -1.4904
## Father_occupationENGINEER         0.1658     0.5315   0.3120
## Father_occupationOTHERS          -0.7566     0.4576  -1.6536
## Father_occupationSCHOOL_TEACHER  -1.1125     0.4887  -2.2762
## 
## Intercepts:
##              Value    Std. Error t value 
## Average|Good  -3.0630   0.5858    -5.2286
## Good|Vg       -0.5193   0.5732    -0.9061
## Vg|Excellent   1.4098   0.5734     2.4588
## 
## Residual Deviance: 1319.739 
## AIC: 1357.739
# Predicciones del modelo
predicciones <- predict(modelo_significativo, newdata = Rendimiento_2)

# Matriz de confusión
matriz_confusion <- table(Predicho = predicciones, Real = Rendimiento_2$Performance)
print(matriz_confusion)
##            Real
## Predicho    Average Good  Vg Excellent
##   Average       110    9   5         0
##   Good           46   97  53        20
##   Vg              1   96 123        61
##   Excellent       0    8  17        20
# Calcular la exactitud del modelo
exactitud <- sum(diag(matriz_confusion)) / sum(matriz_confusion)
cat("La exactitud del modelo es:", round(exactitud * 100, 2), "%\n")
## La exactitud del modelo es: 52.55 %

INTERPRETACIÒN DEL MODELO LOGISTICO

Caste:

OBC (-1.1755, t = -6.09): Ser de la casta OBC está asociado con una menor probabilidad de alcanzar un nivel más alto de desempeño académico en comparación con la categoría base (General), y este efecto es estadísticamente significativo.

SC (-2.6897, t = -9.04): Pertenecer a la casta SC tiene un efecto negativo aún más pronunciado en el rendimiento en comparación con General, con alta significancia estadística.

ST (-5.9851, t = -13.33): La categoría ST muestra el mayor efecto negativo, sugiriendo que los estudiantes de esta casta tienen menor probabilidad de alcanzar niveles superiores de desempeño.

coaching:

OA (coaching asistido ocasionalmente) (1.2482, t = 3.88): Haber recibido coaching ocasional se asocia con una mayor probabilidad de un mejor rendimiento, siendo estadísticamente significativo.

WA (coaching asistido regularmente) (0.2530, t = 1.30): El coaching regular muestra un efecto positivo, aunque menos marcado y no estadísticamente significativo en este modelo.

twelve_education:

CBSE (-0.1297, t = -0.71) y OTHERS (0.3242, t = 0.35): La educación secundaria de tipo CBSE y otras modalidades no presentan efectos estadísticamente significativos en comparación con la categoría base AHSEC.

medium:

ENGLISH (0.7246, t = 2.23): Estudiar en medio inglés está asociado con una mayor probabilidad de lograr un mejor rendimiento académico, y este resultado es estadísticamente significativo.

OTHERS (0.9503, t = 2.58): Otros medios de instrucción también presentan un efecto positivo significativo en el desempeño.

Father_occupation:

BUSINESS (-0.9960, t = -2.06): Tener un padre con ocupación en negocios está relacionado con una menor probabilidad de un mejor rendimiento académico, con significancia estadística.

SCHOOL_TEACHER (-1.1125, t = -2.28): Que el padre sea maestro de escuela también se asocia con un menor rendimiento académico, estadísticamente significativo.

COLLEGE_TEACHER (0.3633, t = 0.64), CULTIVATOR (-1.0068, t = -1.55), DOCTOR (-0.7695, t = -1.49), ENGINEER (0.1658, t = 0.31), OTHERS (-0.7566, t = -1.65): Estas ocupaciones no muestran efectos estadísticamente significativos.

Esta jerarquía basada en los valores t permite identificar qué variables tienen un impacto más sólido y confiable en el desempeño académico, facilitando la toma de decisiones informadas. Las variables con valores t altos en magnitud (por ejemplo, las castas OBC, SC y ST, el coaching ocasional y el medio de instrucción en inglés u otros) destacan como factores clave que influyen significativamente en el rendimiento. Por otro lado, aquellas variables con valores t cercanos a cero sugieren un efecto débil o incierto, por lo que pueden ser consideradas menos relevantes o prescindibles. De esta manera, el valor t no solo evalúa la fuerza estadística del modelo, sino que también guía la selección de variables que aportan valor real al análisis. En esencia, el modelo revela que aspectos específicos como la casta, el tipo de coaching recibido y el medio de instrucción tienen un papel mucho más decisivo en el rendimiento estudiantil que otras características menos significativas.

EVALUACIÓN

# Predicciones del modelo
predicciones <- predict(modelo_significativo, newdata = Rendimiento_2)

# Matriz de confusión
matriz_confusion <- table(Predicho = predicciones, Real = Rendimiento_2$Performance)
print(matriz_confusion)
##            Real
## Predicho    Average Good  Vg Excellent
##   Average       110    9   5         0
##   Good           46   97  53        20
##   Vg              1   96 123        61
##   Excellent       0    8  17        20
# Calcular la exactitud del modelo
exactitud <- sum(diag(matriz_confusion)) / sum(matriz_confusion)
cat("La exactitud del modelo es:", round(exactitud * 100, 2), "%\n")
## La exactitud del modelo es: 52.55 %

La matriz de confusión muestra cómo el modelo clasificó a los estudiantes en las categorías de desempeño: Average, Good, Vg y Excellent, en comparación con sus clasificaciones reales. Por ejemplo, de los estudiantes que realmente tienen un desempeño Average, el modelo predijo correctamente 110 casos, pero clasificó erróneamente a 9 como Good y a 5 como Vg. De manera similar, para la categoría Good, 97 estudiantes fueron correctamente clasificados, aunque 46 se asignaron erróneamente a Average, 53 a Vg y 20 a Excellent. En el grupo Vg, 123 predicciones fueron correctas, pero hubo errores que incluyeron 1 caso clasificado como Average, 96 como Good y 61 como Excellent. Finalmente, en la categoría Excellent, el modelo acertó en 20 casos, mientras que clasificó erróneamente a 8 como Good y 17 como Vg.

Estos resultados reflejan que el modelo tiene una capacidad moderada para distinguir entre las diferentes categorías de desempeño, logrando una exactitud general del 52.55%. Esto significa que aproximadamente la mitad de las predicciones del modelo coinciden con la clasificación real de los estudiantes, indicando que aunque el modelo captura ciertas tendencias, aún hay margen para mejorar su precisión, especialmente en diferenciar claramente entre categorías intermedias como Good y Vg.

DESPLIEGUE

Se ha desarrollado una aplicación interactiva que permite a los usuarios ingresar datos relevantes de los estudiantes, como casta, tipo de coaching, educación en grado 12, medio de instrucción y ocupación del padre, para obtener en tiempo real una predicción del desempeño académico categorizado en Average, Good, Vg o Excellent. Esta herramienta utiliza un modelo logístico ordinal ajustado con las variables más significativas, seleccionadas a través de un análisis riguroso basado en criterios estadísticos como el valor t, lo que garantiza predicciones confiables y útiles para docentes, orientadores y administradores académicos.

La aplicación fue creada siguiendo la metodología CRISP-DM, asegurando que la solución sea robusta, escalable y adaptable a futuros cambios en los datos o en los requerimientos del sistema educativo.

Entre los beneficios clave de esta aplicación se encuentran su capacidad para facilitar la identificación temprana de estudiantes con distintos niveles de desempeño, permitiendo así diseñar estrategias personalizadas de apoyo académico. Además, el modelo cuenta con una exactitud del 52.55%, lo que representa una base sólida para la toma de decisiones informadas. La herramienta también ofrece explicaciones claras sobre las predicciones, facilitando su comprensión y adopción por parte de los usuarios finales.

Al combinar técnicas avanzadas de análisis estadístico con una interfaz amigable, esta aplicación se posiciona como un recurso estratégico para mejorar la gestión educativa, optimizar recursos y potenciar el éxito académico de los estudiantes.

library(shiny)
library(MASS)

# Interfaz de usuario
ui <- fluidPage(
  titlePanel("Predicción de Rendimiento Académico"),
  sidebarLayout(
    sidebarPanel(
      selectInput("caste", "Casta:", 
                  choices = c("General", "OBC", "SC", "ST")),
      selectInput("coaching", "Recibe coaching:", 
                  choices = c("NO", "WA", "OA")),
      selectInput("twelve_education", "Educación secundaria:", 
                  choices = c("AHSEC", "CBSE", "OTHERS")),
      selectInput("medium", "Medio de instrucción:", 
                  choices = c("ENGLISH", "ASSAMESE", "OTHERS")),
      selectInput("father_occupation", "Ocupación del padre:", 
                  choices = c("DOCTOR", "SCHOOL_TEACHER", "COLLEGE_TEACHER", 
                             "BUSINESS", "ENGINEER", "BANK_OFFICIAL", 
                             "CULTIVATOR", "OTHERS")),
      actionButton("predict", "Predecir Rendimiento")
    ),
    mainPanel(
      h3("Resultado de la Predicción:"),
      verbatimTextOutput("prediction"),
      h3("Probabilidades por Categoría:"),
      tableOutput("probabilities")
    )
  )
)

# Lógica del servidor
server <- function(input, output) {
  
  # Cargar el modelo (deberías tenerlo previamente guardado)
  # modelo <- readRDS("modelo_ordinal.rds")
  
  # O crear el modelo aquí mismo (solo para demostración)
  modelo <- reactive({
    # Este es solo un ejemplo - deberías usar tu modelo real
    polr(Performance ~ Caste + coaching + twelve_education + medium + Father_occupation,
         data = Rendimiento_2, Hess = TRUE)
  })
  
  # Hacer la predicción cuando se presiona el botón
  observeEvent(input$predict, {
    # Crear dataframe con los inputs
    new_data <- data.frame(
      Caste = input$caste,
      coaching = input$coaching,
      twelve_education = input$twelve_education,
      medium = input$medium,
      Father_occupation = input$father_occupation
    )
    
    # Hacer la predicción
    pred <- predict(modelo(), newdata = new_data, type = "class")
    probs <- predict(modelo(), newdata = new_data, type = "probs")
    
    # Mostrar resultados
    output$prediction <- renderPrint({
      cat("Rendimiento predicho:", as.character(pred))
    })
    
    output$probabilities <- renderTable({
      data.frame(
        Categoría = c("Excellent", "Vg", "Good", "Average"),
        Probabilidad = round(as.numeric(probs) * 100, 2)
      )
    }, digits = 2)
  })
}

# Ejecutar la aplicación
shinyApp(ui = ui, server = server)
Shiny applications not supported in static R Markdown documents

CONCLUSIÓN

El análisis realizado, basado en un enfoque riguroso de selección de variables y modelado estadístico, permitió construir un modelo logístico ordinal para predecir el desempeño académico de los estudiantes en distintas categorías: Average, Good, Vg y Excellent. Partiendo de un conjunto amplio de variables demográficas, educativas y familiares, se identificaron las más significativas —como la casta, el tipo de coaching recibido, la educación en grado 12, el medio de instrucción y la ocupación del padre— que aportan información valiosa para la predicción del rendimiento.

La evaluación del modelo a través de la matriz de confusión mostró una exactitud del 52.55%, lo que indica un nivel razonable de predicción para esta clase de datos educativos y permite un uso práctico para orientar intervenciones académicas. Además, se desarrolló una aplicación interactiva que facilita la implementación del modelo, permitiendo a usuarios ingresar datos clave y obtener predicciones en tiempo real sobre el desempeño esperado, lo que apoya a docentes y orientadores en la identificación temprana de estudiantes que puedan requerir atención personalizada.

En resumen, este proyecto ofrece un modelo predictivo sólido junto con una herramienta tecnológica accesible, que en conjunto contribuyen a mejorar la gestión educativa y optimizar los recursos para maximizar el éxito estudiantil, todo ello sustentado en un proceso metodológico estructurado y validado estadísticamente.