# Leer archivo csv
datos <- read.csv("/Users/Vale/Desktop/DOCUMENTOS UNIVALLE/1. Primer Semestre/5. Metodos Cuantitativos para el analisis de informacion/Metodos Cuantitativos/Trabajo final/Telco-Customer-Churn.csv")

Pregunta de investigación

¿Qué factores influyen en que un cliente abandone el servicio de telecomunicaciones?

Variable respuesta:

Churn

Yes = Abandona el servicio No = Permanece en la empresa

Objetivo general

Desarrollar un modelo analítico que permita identificar los factores asociados a la cancelación del servicio por parte de los clientes de una empresa de telecomunicaciones.

#——————————————————————————# # 1. Introducción #——————————————————————————#

La pérdida de clientes o churn representa uno de los principales desafíos para las empresas de telecomunicaciones, ya que puede afectar directamente sus ingresos y crecimiento. Por esta razón, identificar los factores asociados al abandono de clientes se ha convertido en un tema de gran interés para las organizaciones.

En este trabajo se utiliza el conjunto de datos Telco Customer Churn, el cual contiene información demográfica, características de los servicios contratados y datos de facturación de más de 7.000 clientes. Esta información permite explorar patrones de comportamiento relacionados con la cancelación del servicio.

El objetivo del análisis es identificar las variables que influyen en el abandono de clientes mediante técnicas de análisis exploratorio de datos y la construcción de un modelo de regresión logística. Asimismo, se evalúa la capacidad predictiva del modelo para clasificar clientes con riesgo de abandono.

#——————————————————————————# # 2. Descripción de la base de datos #——————————————————————————# Para el desarrollo de este trabajo se utilizó el conjunto de datos Telco Customer Churn, disponible en la plataforma Kaggle. Esta base de datos contiene información de clientes de una empresa de telecomunicaciones y tiene como objetivo analizar los factores asociados al abandono del servicio (churn).

La base está compuesta por 7.043 registros y 21 variables, las cuales incluyen características demográficas de los clientes, servicios contratados, información de facturación y la variable objetivo Churn, que indica si el cliente permaneció o abandonó la compañía.

Entre las variables más relevantes se encuentran la antigüedad del cliente (tenure), el tipo de contrato (Contract), el servicio de internet (InternetService), el método de pago (PaymentMethod), los cargos mensuales (MonthlyCharges) y los cargos totales (TotalCharges). Estas variables permiten estudiar el comportamiento de los clientes y desarrollar modelos predictivos para identificar el riesgo de abandono.

data.frame(
  Característica = c("Número de registros",
                     "Número de variables",
                     "Variable objetivo"),
  Valor = c("7043",
            "21",
            "Churn")
)
##        Característica Valor
## 1 Número de registros  7043
## 2 Número de variables    21
## 3   Variable objetivo Churn

#——————————————————————————# # 3. Preprocesamiento de los datos #——————————————————————————# #——————————————————————————# ### 3.1 Conversión de variables #——————————————————————————#

# Revisar estructura
str(datos)
## 'data.frame':    7043 obs. of  21 variables:
##  $ customerID      : chr  "7590-VHVEG" "5575-GNVDE" "3668-QPYBK" "7795-CFOCW" ...
##  $ gender          : chr  "Female" "Male" "Male" "Male" ...
##  $ SeniorCitizen   : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ Partner         : chr  "Yes" "No" "No" "No" ...
##  $ Dependents      : chr  "No" "No" "No" "No" ...
##  $ tenure          : int  1 34 2 45 2 8 22 10 28 62 ...
##  $ PhoneService    : chr  "No" "Yes" "Yes" "No" ...
##  $ MultipleLines   : chr  "No phone service" "No" "No" "No phone service" ...
##  $ InternetService : chr  "DSL" "DSL" "DSL" "DSL" ...
##  $ OnlineSecurity  : chr  "No" "Yes" "Yes" "Yes" ...
##  $ OnlineBackup    : chr  "Yes" "No" "Yes" "No" ...
##  $ DeviceProtection: chr  "No" "Yes" "No" "Yes" ...
##  $ TechSupport     : chr  "No" "No" "No" "Yes" ...
##  $ StreamingTV     : chr  "No" "No" "No" "No" ...
##  $ StreamingMovies : chr  "No" "No" "No" "No" ...
##  $ Contract        : chr  "Month-to-month" "One year" "Month-to-month" "One year" ...
##  $ PaperlessBilling: chr  "Yes" "No" "Yes" "No" ...
##  $ PaymentMethod   : chr  "Electronic check" "Mailed check" "Mailed check" "Bank transfer (automatic)" ...
##  $ MonthlyCharges  : num  29.9 57 53.9 42.3 70.7 ...
##  $ TotalCharges    : num  29.9 1889.5 108.2 1840.8 151.7 ...
##  $ Churn           : chr  "No" "No" "Yes" "No" ...
# Resumen
summary(datos)
##      customerID         gender     SeniorCitizen         Partner    
##  Length   :7043   Length   :7043   Min.   :0.0000   Length   :7043  
##  N.unique :7043   N.unique :   2   1st Qu.:0.0000   N.unique :   2  
##  N.blank  :   0   N.blank  :   0   Median :0.0000   N.blank  :   0  
##  Min.nchar:  10   Min.nchar:   4   Mean   :0.1621   Min.nchar:   2  
##  Max.nchar:  10   Max.nchar:   6   3rd Qu.:0.0000   Max.nchar:   3  
##                                    Max.   :1.0000                   
##                                                                     
##      Dependents       tenure         PhoneService    MultipleLines 
##  Length   :7043   Min.   : 0.00   Length   :7043   Length   :7043  
##  N.unique :   2   1st Qu.: 9.00   N.unique :   2   N.unique :   3  
##  N.blank  :   0   Median :29.00   N.blank  :   0   N.blank  :   0  
##  Min.nchar:   2   Mean   :32.37   Min.nchar:   2   Min.nchar:   2  
##  Max.nchar:   3   3rd Qu.:55.00   Max.nchar:   3   Max.nchar:  16  
##                   Max.   :72.00                                    
##                                                                    
##   InternetService   OnlineSecurity    OnlineBackup   DeviceProtection
##  Length   :7043   Length   :7043   Length   :7043   Length   :7043   
##  N.unique :   3   N.unique :   3   N.unique :   3   N.unique :   3   
##  N.blank  :   0   N.blank  :   0   N.blank  :   0   N.blank  :   0   
##  Min.nchar:   2   Min.nchar:   2   Min.nchar:   2   Min.nchar:   2   
##  Max.nchar:  11   Max.nchar:  19   Max.nchar:  19   Max.nchar:  19   
##                                                                      
##                                                                      
##     TechSupport      StreamingTV    StreamingMovies      Contract   
##  Length   :7043   Length   :7043   Length   :7043   Length   :7043  
##  N.unique :   3   N.unique :   3   N.unique :   3   N.unique :   3  
##  N.blank  :   0   N.blank  :   0   N.blank  :   0   N.blank  :   0  
##  Min.nchar:   2   Min.nchar:   2   Min.nchar:   2   Min.nchar:   8  
##  Max.nchar:  19   Max.nchar:  19   Max.nchar:  19   Max.nchar:  14  
##                                                                     
##                                                                     
##   PaperlessBilling   PaymentMethod  MonthlyCharges    TotalCharges   
##  Length   :7043    Length   :7043   Min.   : 18.25   Min.   :  18.8  
##  N.unique :   2    N.unique :   4   1st Qu.: 35.50   1st Qu.: 401.4  
##  N.blank  :   0    N.blank  :   0   Median : 70.35   Median :1397.5  
##  Min.nchar:   2    Min.nchar:  12   Mean   : 64.76   Mean   :2283.3  
##  Max.nchar:   3    Max.nchar:  25   3rd Qu.: 89.85   3rd Qu.:3794.7  
##                                     Max.   :118.75   Max.   :8684.8  
##                                                      NAs    :11      
##        Churn     
##  Length   :7043  
##  N.unique :   2  
##  N.blank  :   0  
##  Min.nchar:   2  
##  Max.nchar:   3  
##                  
## 
# Nombres de variables
names(datos)
##  [1] "customerID"       "gender"           "SeniorCitizen"    "Partner"         
##  [5] "Dependents"       "tenure"           "PhoneService"     "MultipleLines"   
##  [9] "InternetService"  "OnlineSecurity"   "OnlineBackup"     "DeviceProtection"
## [13] "TechSupport"      "StreamingTV"      "StreamingMovies"  "Contract"        
## [17] "PaperlessBilling" "PaymentMethod"    "MonthlyCharges"   "TotalCharges"    
## [21] "Churn"

#——————————————————————————# # Convertir variables categóricas a factor #——————————————————————————#

datos$gender            <- factor(datos$gender)
datos$Partner           <- factor(datos$Partner)
datos$Dependents        <- factor(datos$Dependents)
datos$PhoneService      <- factor(datos$PhoneService)
datos$MultipleLines     <- factor(datos$MultipleLines)
datos$InternetService   <- factor(datos$InternetService)
datos$OnlineSecurity    <- factor(datos$OnlineSecurity)
datos$OnlineBackup      <- factor(datos$OnlineBackup)
datos$DeviceProtection  <- factor(datos$DeviceProtection)
datos$TechSupport       <- factor(datos$TechSupport)
datos$StreamingTV       <- factor(datos$StreamingTV)
datos$StreamingMovies   <- factor(datos$StreamingMovies)
datos$Contract          <- factor(datos$Contract)
datos$PaperlessBilling  <- factor(datos$PaperlessBilling)
datos$PaymentMethod     <- factor(datos$PaymentMethod)
datos$Churn             <- factor(datos$Churn)

# Revisar estructura nuevamente
str(datos)
## 'data.frame':    7043 obs. of  21 variables:
##  $ customerID      : chr  "7590-VHVEG" "5575-GNVDE" "3668-QPYBK" "7795-CFOCW" ...
##  $ gender          : Factor w/ 2 levels "Female","Male": 1 2 2 2 1 1 2 1 1 2 ...
##  $ SeniorCitizen   : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ Partner         : Factor w/ 2 levels "No","Yes": 2 1 1 1 1 1 1 1 2 1 ...
##  $ Dependents      : Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 2 1 1 2 ...
##  $ tenure          : int  1 34 2 45 2 8 22 10 28 62 ...
##  $ PhoneService    : Factor w/ 2 levels "No","Yes": 1 2 2 1 2 2 2 1 2 2 ...
##  $ MultipleLines   : Factor w/ 3 levels "No","No phone service",..: 2 1 1 2 1 3 3 2 3 1 ...
##  $ InternetService : Factor w/ 3 levels "DSL","Fiber optic",..: 1 1 1 1 2 2 2 1 2 1 ...
##  $ OnlineSecurity  : Factor w/ 3 levels "No","No internet service",..: 1 3 3 3 1 1 1 3 1 3 ...
##  $ OnlineBackup    : Factor w/ 3 levels "No","No internet service",..: 3 1 3 1 1 1 3 1 1 3 ...
##  $ DeviceProtection: Factor w/ 3 levels "No","No internet service",..: 1 3 1 3 1 3 1 1 3 1 ...
##  $ TechSupport     : Factor w/ 3 levels "No","No internet service",..: 1 1 1 3 1 1 1 1 3 1 ...
##  $ StreamingTV     : Factor w/ 3 levels "No","No internet service",..: 1 1 1 1 1 3 3 1 3 1 ...
##  $ StreamingMovies : Factor w/ 3 levels "No","No internet service",..: 1 1 1 1 1 3 1 1 3 1 ...
##  $ Contract        : Factor w/ 3 levels "Month-to-month",..: 1 2 1 2 1 1 1 1 1 2 ...
##  $ PaperlessBilling: Factor w/ 2 levels "No","Yes": 2 1 2 1 2 2 2 1 2 1 ...
##  $ PaymentMethod   : Factor w/ 4 levels "Bank transfer (automatic)",..: 3 4 4 1 3 3 2 4 3 1 ...
##  $ MonthlyCharges  : num  29.9 57 53.9 42.3 70.7 ...
##  $ TotalCharges    : num  29.9 1889.5 108.2 1840.8 151.7 ...
##  $ Churn           : Factor w/ 2 levels "No","Yes": 1 1 2 1 2 2 1 1 2 1 ...
if (!require("pacman")) install.packages("pacman")
## Loading required package: pacman
pacman::p_load( naniar, visdat)

#——————————————————————————# ### 3.2 Análisis de datos faltantes #——————————————————————————#

pacman::p_load(ggplot2, naniar, visdat)

# Visualización de faltantes
naniar::vis_miss(datos) +
  theme(axis.text.x = element_text(size = 9, angle = 60, hjust = 1)) +
  labs(title = "Visualización de datos faltantes")

#Resumen de faltantes
naniar::miss_var_summary(datos)
## # A tibble: 21 × 3
##    variable        n_miss pct_miss
##    <chr>            <int>    <num>
##  1 TotalCharges        11    0.156
##  2 customerID           0    0    
##  3 gender               0    0    
##  4 SeniorCitizen        0    0    
##  5 Partner              0    0    
##  6 Dependents           0    0    
##  7 tenure               0    0    
##  8 PhoneService         0    0    
##  9 MultipleLines        0    0    
## 10 InternetService      0    0    
## # ℹ 11 more rows
sum(is.na(datos$TotalCharges))
## [1] 11

La exploración de valores faltantes mostró que la base de datos presenta una alta calidad de información. Únicamente la variable TotalCharges contiene valores faltantes, con un total de 11 registros sobre 7043 observaciones, lo que representa menos del 0.2% de la muestra.

Dado que la proporción de datos faltantes es mínima, se considera razonable eliminar dichos registros sin afectar significativamente los resultados del análisis posterior.

#——————————————————————————# ### 3.3. Tratamiento de valores faltantes #——————————————————————————#

# Tratamiento datos faltantes
datos <- na.omit(datos)

# Verificar tamaño final
dim(datos)
## [1] 7032   21
# Confirmar que ya no existen faltantes
sum(is.na(datos))
## [1] 0

3.1 Revisión de la estructura de los datos

Inicialmente se realizó una exploración de la base de datos con el fin de identificar la estructura, los tipos de variables y posibles problemas de calidad de la información. La base contiene 7043 observaciones y 21 variables, incluyendo información demográfica, características de los servicios contratados, información de facturación y la variable objetivo Churn, que indica si el cliente abandonó o no el servicio.

Posteriormente, las variables categóricas fueron convertidas al tipo factor para facilitar su análisis y permitir su utilización en modelos estadísticos.

3.2 Identificación de datos faltantes

Se realizó una inspección de los valores faltantes mediante herramientas gráficas y resúmenes tabulares. Los resultados mostraron que únicamente la variable TotalCharges presentaba datos ausentes.

Se identificaron 11 valores faltantes en la variable TotalCharges, correspondientes a una proporción inferior al 0.2% de la base de datos. Debido a que la cantidad de registros incompletos es mínima, se decidió eliminarlos mediante la función na.omit().

Esta decisión permite trabajar con una base completa sin afectar de manera significativa el tamaño de la muestra ni la representatividad de los datos. Después del proceso de depuración, la base final quedó conformada por 7032 observaciones y 21 variables, sin presencia de valores faltantes.

Por esta razón, en lugar de aplicar métodos de imputación, se optó por eliminar los registros incompletos mediante la función na.omit(), obteniendo una base final de 7032 observaciones sin valores faltantes.

Después de este proceso de depuración, la base final quedó conformada por 7032 observaciones y 21 variables, sin presencia de valores faltantes.

Una vez completada la etapa de preprocesamiento, se procedió al análisis descriptivo de las variables con el fin de comprender la composición de la muestra e identificar posibles patrones asociados al abandono de clientes.

#——————————————————————————# # 4. Análisis descriptivo #——————————————————————————# #——————————————————————————# ### 4.1. Distribución de la variable Churn #——————————————————————————#

# Distribución de Churn
table(datos$Churn)
## 
##   No  Yes 
## 5163 1869
prop.table(table(datos$Churn))*100
## 
##      No     Yes 
## 73.4215 26.5785
ggplot(datos, aes(x = Churn, fill = Churn)) +
  geom_bar() +
  theme_bw() +
  labs( title = "Distribución de clientes según Churn", x = "Churn",y = "Frecuencia")

La variable Churn representa el abandono del servicio por parte de los clientes y constituye la variable objetivo del presente análisis.

Los resultados muestran que de los 7032 clientes analizados, 5163 (73.42%) permanecen en la compañía, mientras que 1869 (26.58%) abandonaron el servicio.

El gráfico evidencia una clara predominancia de clientes que continúan vinculados a la empresa. Sin embargo, el porcentaje de abandono no es despreciable, ya que aproximadamente uno de cada cuatro clientes cancela el servicio.

Este resultado confirma la relevancia del problema de negocio y justifica la construcción de modelos analíticos orientados a identificar los factores asociados al abandono de clientes.

#——————————————————————————# ### 4.2. Distribución del tipo de contrato #——————————————————————————#

# 4.2 - Distribución del tipo de contrato
table(datos$Contract)
## 
## Month-to-month       One year       Two year 
##           3875           1472           1685
prop.table(table(datos$Contract))*100
## 
## Month-to-month       One year       Two year 
##       55.10523       20.93288       23.96189
ggplot(datos, aes(x = Contract, fill = Contract)) +
  geom_bar() +
  theme_bw() +
  labs( title = "Distribución de clientes por tipo de contrato",
    x = "Tipo de contrato",
    y = "Frecuencia" )

La variable Contract describe la modalidad de contratación de los clientes. Los resultados muestran que la mayoría de los usuarios posee contratos de tipo Month-to-month, con 3875 clientes (55.11% de la muestra).

Por su parte, los contratos de One year representan el 20.93% de los clientes, mientras que los contratos de Two year corresponden al 23.96%.

La distribución observada indica una alta concentración de clientes con contratos de corto plazo. Desde una perspectiva de negocio, este comportamiento puede resultar relevante, ya que los contratos mensuales suelen ofrecer menor compromiso de permanencia y podrían estar asociados con mayores tasas de abandono del servicio.

#——————————————————————————# ### 4.3. Facturación mensual #——————————————————————————#

#4.3 - Facturación mensual
summary(datos$MonthlyCharges)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   18.25   35.59   70.35   64.80   89.86  118.75
ggplot(datos, aes(x = MonthlyCharges)) +
  geom_histogram(bins = 30, fill = "steelblue", color = "white") +
  theme_bw() +
  labs(title = "Distribución de la facturación mensual",
    x = "Monthly Charges",
    y = "Frecuencia")

ggplot(datos, aes(y = MonthlyCharges)) +
  geom_boxplot(fill = "lightblue") +
  theme_bw() +
  labs(title = "Boxplot de Monthly Charges",
    y = "Monthly Charges" )

La facturación mensual presenta valores entre 18.25 y 118.75, con una media de 64.80 y una mediana de 70.35. Esto indica que la mayoría de clientes se concentra en cargos mensuales intermedios y altos.

El boxplot muestra una dispersión amplia en los valores de facturación, aunque no se observan valores atípicos extremos. Esta variable puede ser relevante para explicar el abandono, ya que mayores cargos mensuales podrían estar asociados con una mayor probabilidad de cancelación del servicio.

#——————————————————————————# # 5. Análisis bivariado #——————————————————————————# #——————————————————————————# ### 5.1. Relación entre el abandono y el tipo de contrato #——————————————————————————#

# 5.1 - Churn vs Contract
tabla_contract <- table(datos$Contract, datos$Churn)

tabla_contract
##                 
##                    No  Yes
##   Month-to-month 2220 1655
##   One year       1306  166
##   Two year       1637   48
prop.table(tabla_contract, margin = 1) * 100
##                 
##                         No       Yes
##   Month-to-month 57.290323 42.709677
##   One year       88.722826 11.277174
##   Two year       97.151335  2.848665
ggplot(datos, aes(x = Contract, fill = Churn)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("#1C5A99", "#CD5555")) +
  theme_bw() +
  labs(
    title = "Proporción de abandono según tipo de contrato",
    x = "Tipo de contrato",
    y = "Porcentaje",
    fill = "Churn"
  ) +
  theme(plot.title = element_text(face = "bold"))

Con el fin de evaluar la posible asociación entre el tipo de contrato y el abandono del servicio, se analizó la distribución de la variable Churn dentro de cada modalidad de contratación.

Los resultados muestran diferencias importantes entre los grupos. En los clientes con contratos mensuales (Month-to-month), el 42.71% abandonó el servicio, mientras que en los contratos de un año (One year) el porcentaje de abandono fue de 11.28%. Por su parte, los contratos de dos años (Two year) presentaron la menor tasa de cancelación, con apenas un 2.85%.

El gráfico de proporciones confirma que el abandono disminuye considerablemente a medida que aumenta la duración del contrato. Este comportamiento sugiere que la permanencia contractual constituye un factor importante para la retención de clientes y podría ser una de las variables con mayor capacidad explicativa dentro del modelo predictivo.

#——————————————————————————# ### 5.2 Relación entre el abandono y el servicio de internet #——————————————————————————#

# 5.2 - Churn vs InternetService
tabla_internet <- table(datos$InternetService, datos$Churn)

tabla_internet
##              
##                 No  Yes
##   DSL         1957  459
##   Fiber optic 1799 1297
##   No          1407  113
prop.table(tabla_internet, margin = 1) * 100
##              
##                      No       Yes
##   DSL         81.001656 18.998344
##   Fiber optic 58.107235 41.892765
##   No          92.565789  7.434211
ggplot(datos, aes(x = InternetService, fill = Churn)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("#1C5A99", "#CD5555")) +
  theme_bw() +
  labs(
    title = "Proporción de abandono según servicio de internet",
    x = "Tipo de servicio",
    y = "Porcentaje",
    fill = "Churn"
  ) +
  theme(plot.title = element_text(face = "bold"))

Los resultados muestran diferencias significativas entre las distintas categorías.

Los clientes con servicio de fibra óptica (Fiber optic) presentan la mayor tasa de abandono, alcanzando un 41.89%. En contraste, los usuarios con servicio DSL registran una tasa de cancelación de 19.00%, mientras que los clientes que no poseen servicio de internet presentan el menor porcentaje de abandono, con apenas un 7.43%.

El gráfico de proporciones evidencia que los usuarios de fibra óptica tienen una probabilidad considerablemente mayor de abandonar la compañía en comparación con los demás grupos. Este comportamiento sugiere que el tipo de servicio de internet podría estar asociado con factores como el precio, la calidad percibida o las expectativas del cliente, convirtiéndose en una variable potencialmente relevante para explicar el abandono.

#——————————————————————————# ### 5.3. Relación entre el abandono y la facturación mensual #——————————————————————————#

# 5.3 - Churn vs MonthlyCharges

ggplot(datos, aes(x = Churn,
                  y = MonthlyCharges,
                  fill = Churn)) +
  geom_boxplot(alpha = 0.8) +
  scale_fill_manual(values = c("#1C5A99", "#CD5555")) +
  theme_bw() +
  labs(
    title = "Facturación mensual según abandono",
    x = "Churn",
    y = "Facturación mensual"
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    legend.position = "none"  )

aggregate(MonthlyCharges ~ Churn,
          data = datos,
          FUN = mean)
##   Churn MonthlyCharges
## 1    No       61.30741
## 2   Yes       74.44133

Con el fin de evaluar la posible asociación entre la facturación mensual y el abandono del servicio, se comparó la distribución de la variable MonthlyCharges entre los clientes que permanecieron en la compañía y aquellos que cancelaron el servicio.

Los resultados muestran que los clientes que abandonaron la empresa presentan una facturación mensual promedio de 74.44 unidades monetarias, mientras que los clientes que permanecieron registran un promedio de 61.31 unidades monetarias.

El boxplot evidencia que la distribución de los cargos mensuales de los clientes que abandonan el servicio se encuentra desplazada hacia valores más altos. Este comportamiento sugiere que los clientes con mayores costos mensuales tienden a presentar una mayor probabilidad de cancelación.

Por lo tanto, la variable MonthlyCharges podría constituir un factor relevante para explicar el abandono de clientes y será incluida en el modelo predictivo.

#——————————————————————————# ### 5.4. Relación entre el abandono y la antigüedad del cliente #——————————————————————————#

# 5.4 - Churn vs Tenure
summary(datos$tenure)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    1.00    9.00   29.00   32.42   55.00   72.00
ggplot(datos, aes(x = Churn, y = tenure, fill = Churn)) +
  geom_boxplot(alpha = 0.8) +
  scale_fill_manual(values = c("#1C5A99", "#CD5555")) +
  theme_bw() +
  labs(title = "Antigüedad del cliente según abandono",
       x = "Churn",
       y = "Antigüedad del cliente") +
  theme(plot.title = element_text(face = "bold"),
        legend.position = "none")

aggregate(tenure ~ Churn, data = datos, FUN = mean)
##   Churn   tenure
## 1    No 37.65001
## 2   Yes 17.97913

La antigüedad promedio de los clientes que permanecen en la compañía es de 37.65 meses, mientras que los clientes que abandonan el servicio presentan una permanencia promedio de 17.98 meses.

El boxplot confirma que los clientes con menor tiempo de permanencia tienden a abandonar con mayor frecuencia, mientras que los clientes más antiguos muestran una mayor fidelización.

Estos resultados sugieren que la variable tenure podría ser un factor importante para explicar el abandono de clientes.

#——————————————————————————# ### 5.5. Relación entre el abandono y el método de pago #——————————————————————————#

# 5.5 - Churn vs PaymentMethod
tabla_pago <- table(datos$PaymentMethod, datos$Churn)

tabla_pago
##                            
##                               No  Yes
##   Bank transfer (automatic) 1284  258
##   Credit card (automatic)   1289  232
##   Electronic check          1294 1071
##   Mailed check              1296  308
prop.table(tabla_pago, margin = 1) * 100
##                            
##                                   No      Yes
##   Bank transfer (automatic) 83.26848 16.73152
##   Credit card (automatic)   84.74688 15.25312
##   Electronic check          54.71459 45.28541
##   Mailed check              80.79800 19.20200
ggplot(datos, aes(x = PaymentMethod, fill = Churn)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("#1C5A99", "#CD5555")) +
  theme_bw() +
  labs(
    title = "Proporción de abandono según método de pago",
    x = "Método de pago",
    y = "Porcentaje",
    fill = "Churn"
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    axis.text.x = element_text(angle = 25, hjust = 1)
  )

Los resultados muestran que los clientes que utilizan Electronic check presentan la mayor tasa de cancelación, alcanzando un 45.29%.

En contraste, los métodos de pago automáticos registran los menores porcentajes de abandono, con tasas de 16.73% para Bank transfer (automatic) y 15.25% para Credit card (automatic). Por su parte, los clientes que utilizan Mailed check presentan una tasa de abandono de 19.20%.

Estos resultados sugieren que el método de pago podría estar asociado al comportamiento de permanencia de los clientes y podría aportar información relevante para el modelo predictivo.

#——————————————————————————# ### 5.6. Relación entre el abandono y el soporte técnico #——————————————————————————#

# 5.6 - Churn vs TechSupport
tabla_soporte <- table(datos$TechSupport, datos$Churn)

tabla_soporte
##                      
##                         No  Yes
##   No                  2026 1446
##   No internet service 1407  113
##   Yes                 1730  310
prop.table(tabla_soporte, margin = 1) * 100
##                      
##                              No       Yes
##   No                  58.352535 41.647465
##   No internet service 92.565789  7.434211
##   Yes                 84.803922 15.196078
ggplot(datos, aes(x = TechSupport, fill = Churn)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("#1C5A99", "#CD5555")) +
  theme_bw() +
  labs(
    title = "Proporción de abandono según soporte técnico",
    x = "Soporte técnico",
    y = "Porcentaje",
    fill = "Churn"
  ) +
  theme(plot.title = element_text(face = "bold"))

Los resultados muestran que los clientes que no cuentan con soporte técnico presentan una tasa de abandono de 41.65%, considerablemente superior a la observada en los clientes que sí disponen de este servicio (15.20%).

Por otra parte, los usuarios que no cuentan con servicio de internet registran una tasa de abandono de apenas 7.43%.

Estos resultados sugieren que la disponibilidad de soporte técnico podría contribuir a la permanencia de los clientes y constituir una variable importante para explicar el abandono del servicio.

#——————————————————————————# ### 5.7. Correlación entre variables numéricas #——————————————————————————#

# 5.7 - Correlaciones entre variables numéricas

pacman::p_load(corrplot)

datos_num <- datos[, c("tenure", "MonthlyCharges", "TotalCharges")]

cor(datos_num)
##                   tenure MonthlyCharges TotalCharges
## tenure         1.0000000      0.2468618    0.8258805
## MonthlyCharges 0.2468618      1.0000000    0.6510648
## TotalCharges   0.8258805      0.6510648    1.0000000
corrplot::corrplot(cor(datos_num),
                   method = "number",
                   type = "upper",
                   number.cex = 0.9,
                   tl.col = "black")

pairs(datos_num, panel = panel.smooth, pch = 16)

Se evaluó la relación entre las variables numéricas tenure, MonthlyCharges y TotalCharges mediante una matriz de correlaciones de Pearson.

Los resultados muestran una correlación fuerte y positiva entre tenure y TotalCharges (r = 0.83), lo cual es esperado, ya que los clientes con mayor antigüedad acumulan una mayor facturación total. Asimismo, se observa una correlación moderada entre MonthlyCharges y TotalCharges (r = 0.65).

Por otra parte, la relación entre tenure y MonthlyCharges es débil (r = 0.25), lo que indica que la antigüedad del cliente no está fuertemente asociada con el valor de la facturación mensual.

En general, las correlaciones observadas no sugieren problemas severos de redundancia entre las variables explicativas que serán consideradas en el modelo.

#——————————————————————————# # 6. Modelo de regresión logística #——————————————————————————# #——————————————————————————# ### 6.1. Modelo logístico saturado #——————————————————————————#

# 6.1 - Modelo logístico saturado
mod1 <- glm(
  Churn ~ gender +
    SeniorCitizen +
    Partner +
    Dependents +
    tenure +
    PhoneService +
    MultipleLines +
    InternetService +
    OnlineSecurity +
    OnlineBackup +
    DeviceProtection +
    TechSupport +
    StreamingTV +
    StreamingMovies +
    Contract +
    PaperlessBilling +
    PaymentMethod +
    MonthlyCharges +
    TotalCharges,
  data = datos,
  family = binomial
)

summary(mod1)
## 
## Call:
## glm(formula = Churn ~ gender + SeniorCitizen + Partner + Dependents + 
##     tenure + PhoneService + MultipleLines + InternetService + 
##     OnlineSecurity + OnlineBackup + DeviceProtection + TechSupport + 
##     StreamingTV + StreamingMovies + Contract + PaperlessBilling + 
##     PaymentMethod + MonthlyCharges + TotalCharges, family = binomial, 
##     data = datos)
## 
## Coefficients: (7 not defined because of singularities)
##                                        Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                           1.165e+00  8.151e-01   1.430  0.15284    
## genderMale                           -2.183e-02  6.480e-02  -0.337  0.73619    
## SeniorCitizen                         2.168e-01  8.453e-02   2.564  0.01033 *  
## PartnerYes                           -3.840e-04  7.783e-02  -0.005  0.99606    
## DependentsYes                        -1.485e-01  8.973e-02  -1.655  0.09796 .  
## tenure                               -6.059e-02  6.236e-03  -9.716  < 2e-16 ***
## PhoneServiceYes                       1.715e-01  6.487e-01   0.264  0.79153    
## MultipleLinesNo phone service                NA         NA      NA       NA    
## MultipleLinesYes                      4.484e-01  1.773e-01   2.530  0.01142 *  
## InternetServiceFiber optic            1.747e+00  7.981e-01   2.190  0.02855 *  
## InternetServiceNo                    -1.786e+00  8.073e-01  -2.213  0.02691 *  
## OnlineSecurityNo internet service            NA         NA      NA       NA    
## OnlineSecurityYes                    -2.054e-01  1.787e-01  -1.150  0.25031    
## OnlineBackupNo internet service              NA         NA      NA       NA    
## OnlineBackupYes                       2.604e-02  1.754e-01   0.148  0.88197    
## DeviceProtectionNo internet service          NA         NA      NA       NA    
## DeviceProtectionYes                   1.474e-01  1.764e-01   0.836  0.40339    
## TechSupportNo internet service               NA         NA      NA       NA    
## TechSupportYes                       -1.805e-01  1.806e-01  -0.999  0.31759    
## StreamingTVNo internet service               NA         NA      NA       NA    
## StreamingTVYes                        5.905e-01  3.263e-01   1.810  0.07035 .  
## StreamingMoviesNo internet service           NA         NA      NA       NA    
## StreamingMoviesYes                    5.993e-01  3.267e-01   1.834  0.06658 .  
## ContractOne year                     -6.608e-01  1.076e-01  -6.142 8.15e-10 ***
## ContractTwo year                     -1.357e+00  1.764e-01  -7.691 1.46e-14 ***
## PaperlessBillingYes                   3.424e-01  7.450e-02   4.596 4.31e-06 ***
## PaymentMethodCredit card (automatic) -8.779e-02  1.141e-01  -0.770  0.44156    
## PaymentMethodElectronic check         3.045e-01  9.450e-02   3.222  0.00127 ** 
## PaymentMethodMailed check            -5.759e-02  1.149e-01  -0.501  0.61627    
## MonthlyCharges                       -4.034e-02  3.176e-02  -1.270  0.20392    
## TotalCharges                          3.289e-04  7.063e-05   4.657 3.20e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 5826.3  on 7008  degrees of freedom
## AIC: 5874.3
## 
## Number of Fisher Scoring iterations: 6

El modelo logístico inicial incluyó todas las variables potencialmente explicativas disponibles en la base de datos. Los resultados preliminares mostraron que algunas variables presentaron significancia estadística, mientras que otras no aportaron evidencia suficiente para explicar el abandono de clientes. Además, ciertas categorías fueron eliminadas automáticamente debido a problemas de redundancia entre variables.

#——————————————————————————# ### 6.2. ANOVA del modelo #——————————————————————————#

# 6.2 - ANOVA del modelo

anova(mod1, test = "Chisq")
## Analysis of Deviance Table
## 
## Model: binomial, link: logit
## 
## Response: Churn
## 
## Terms added sequentially (first to last)
## 
## 
##                  Df Deviance Resid. Df Resid. Dev  Pr(>Chi)    
## NULL                              7031     8143.4              
## gender            1     0.51      7030     8142.8 0.4736720    
## SeniorCitizen     1   148.11      7029     7994.7 < 2.2e-16 ***
## Partner           1   169.58      7028     7825.2 < 2.2e-16 ***
## Dependents        1    46.34      7027     7778.8 9.947e-12 ***
## tenure            1   849.12      7026     6929.7 < 2.2e-16 ***
## PhoneService      1     1.26      7025     6928.4 0.2615613    
## MultipleLines     1   182.63      7024     6745.8 < 2.2e-16 ***
## InternetService   2   631.06      7022     6114.7 < 2.2e-16 ***
## OnlineSecurity    1    45.11      7021     6069.6 1.859e-11 ***
## OnlineBackup      1     2.34      7020     6067.3 0.1258954    
## DeviceProtection  1     0.26      7019     6067.0 0.6090274    
## TechSupport       1    30.17      7018     6036.8 3.953e-08 ***
## StreamingTV       1    26.56      7017     6010.3 2.552e-07 ***
## StreamingMovies   1    13.28      7016     5997.0 0.0002682 ***
## Contract          2    98.94      7014     5898.1 < 2.2e-16 ***
## PaperlessBilling  1    23.02      7013     5875.0 1.604e-06 ***
## PaymentMethod     3    24.94      7010     5850.1 1.589e-05 ***
## MonthlyCharges    1     1.04      7009     5849.1 0.3084696    
## TotalCharges      1    22.80      7008     5826.3 1.801e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Modelo depurado

mod2 <- glm(
  Churn ~ SeniorCitizen +
    Partner +
    Dependents +
    tenure +
    MultipleLines +
    InternetService +
    Contract +
    PaperlessBilling +
    PaymentMethod +
    MonthlyCharges +
    TotalCharges,
  data = datos,
  family = binomial
)

summary(mod2)
## 
## Call:
## glm(formula = Churn ~ SeniorCitizen + Partner + Dependents + 
##     tenure + MultipleLines + InternetService + Contract + PaperlessBilling + 
##     PaymentMethod + MonthlyCharges + TotalCharges, family = binomial, 
##     data = datos)
## 
## Coefficients:
##                                        Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                          -0.7396135  0.2594222  -2.851 0.004358 ** 
## SeniorCitizen                         0.2559113  0.0836629   3.059 0.002222 ** 
## PartnerYes                            0.0033943  0.0771585   0.044 0.964911    
## DependentsYes                        -0.1655686  0.0890106  -1.860 0.062871 .  
## tenure                               -0.0614016  0.0062248  -9.864  < 2e-16 ***
## MultipleLinesNo phone service         0.7190631  0.1456254   4.938 7.90e-07 ***
## MultipleLinesYes                      0.2763893  0.0812198   3.403 0.000667 ***
## InternetServiceFiber optic            0.8927981  0.1339528   6.665 2.65e-11 ***
## InternetServiceNo                    -0.5167925  0.1885513  -2.741 0.006128 ** 
## ContractOne year                     -0.7072131  0.1065546  -6.637 3.20e-11 ***
## ContractTwo year                     -1.5122738  0.1749586  -8.644  < 2e-16 ***
## PaperlessBillingYes                   0.3801288  0.0736395   5.162 2.44e-07 ***
## PaymentMethodCredit card (automatic) -0.0979784  0.1131805  -0.866 0.386665    
## PaymentMethodElectronic check         0.3658765  0.0934620   3.915 9.05e-05 ***
## PaymentMethodMailed check            -0.0799468  0.1138720  -0.702 0.482632    
## MonthlyCharges                        0.0004977  0.0041357   0.120 0.904213    
## TotalCharges                          0.0003084  0.0000704   4.380 1.19e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 5895.7  on 7015  degrees of freedom
## AIC: 5929.7
## 
## Number of Fisher Scoring iterations: 6

#——————————————————————————# ### 6.3 - Multicolinealidad #——————————————————————————#

# Paso 6.3 - Multicolinealidad
car::vif(mod2)
##                       GVIF Df GVIF^(1/(2*Df))
## SeniorCitizen     1.129540  1        1.062798
## Partner           1.374350  1        1.172327
## Dependents        1.284307  1        1.133273
## tenure           15.902635  1        3.987811
## MultipleLines     2.610544  2        1.271109
## InternetService   9.050809  2        1.734490
## Contract          1.564541  2        1.118399
## PaperlessBilling  1.118105  1        1.057405
## PaymentMethod     1.354437  3        1.051864
## MonthlyCharges   11.934354  1        3.454613
## TotalCharges     20.538439  1        4.531936

#——————————————————————————# ### 6.4 - Modelo reducido #——————————————————————————#

#6.4 - Modelo reducido
mod3 <- glm(
  Churn ~ SeniorCitizen + Dependents + tenure + MultipleLines +
    InternetService + Contract + PaperlessBilling + PaymentMethod +
    TotalCharges,
  data = datos,
  family = binomial)

summary(mod3)
## 
## Call:
## glm(formula = Churn ~ SeniorCitizen + Dependents + tenure + MultipleLines + 
##     InternetService + Contract + PaperlessBilling + PaymentMethod + 
##     TotalCharges, family = binomial, data = datos)
## 
## Coefficients:
##                                        Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                          -7.117e-01  1.232e-01  -5.775 7.68e-09 ***
## SeniorCitizen                         2.561e-01  8.311e-02   3.082 0.002057 ** 
## DependentsYes                        -1.637e-01  8.078e-02  -2.026 0.042758 *  
## tenure                               -6.161e-02  5.915e-03 -10.416  < 2e-16 ***
## MultipleLinesNo phone service         7.112e-01  1.298e-01   5.479 4.28e-08 ***
## MultipleLinesYes                      2.788e-01  7.890e-02   3.533 0.000411 ***
## InternetServiceFiber optic            9.042e-01  9.528e-02   9.490  < 2e-16 ***
## InternetServiceNo                    -5.331e-01  1.309e-01  -4.074 4.62e-05 ***
## ContractOne year                     -7.053e-01  1.054e-01  -6.692 2.20e-11 ***
## ContractTwo year                     -1.510e+00  1.741e-01  -8.673  < 2e-16 ***
## PaperlessBillingYes                   3.806e-01  7.352e-02   5.178 2.25e-07 ***
## PaymentMethodCredit card (automatic) -9.815e-02  1.131e-01  -0.868 0.385617    
## PaymentMethodElectronic check         3.660e-01  9.344e-02   3.917 8.98e-05 ***
## PaymentMethodMailed check            -8.102e-02  1.136e-01  -0.713 0.475545    
## TotalCharges                          3.122e-04  6.293e-05   4.961 7.01e-07 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 5895.7  on 7017  degrees of freedom
## AIC: 5925.7
## 
## Number of Fisher Scoring iterations: 6
car::vif(mod3)
##                       GVIF Df GVIF^(1/(2*Df))
## SeniorCitizen     1.114782  1        1.055833
## Dependents        1.057887  1        1.028536
## tenure           14.364531  1        3.790057
## MultipleLines     1.906879  2        1.175116
## InternetService   2.353659  2        1.238614
## Contract          1.525762  2        1.111403
## PaperlessBilling  1.114322  1        1.055615
## PaymentMethod     1.340835  3        1.050096
## TotalCharges     16.420821  1        4.052261

#——————————————————————————# ### 6.5 - Comparación entre modelo depurado y modelo reducido #——————————————————————————#

# 6.5 - Comparación entre modelo depurado y modelo reducido
anova(mod3, mod2, test = "Chisq")
## Analysis of Deviance Table
## 
## Model 1: Churn ~ SeniorCitizen + Dependents + tenure + MultipleLines + 
##     InternetService + Contract + PaperlessBilling + PaymentMethod + 
##     TotalCharges
## Model 2: Churn ~ SeniorCitizen + Partner + Dependents + tenure + MultipleLines + 
##     InternetService + Contract + PaperlessBilling + PaymentMethod + 
##     MonthlyCharges + TotalCharges
##   Resid. Df Resid. Dev Df Deviance Pr(>Chi)
## 1      7017     5895.7                     
## 2      7015     5895.7  2 0.016635   0.9917

Comparación de modelos

Con el fin de obtener un modelo más simple e interpretable, se comparó el modelo depurado con un modelo reducido en el que se eliminaron las variables Partner y MonthlyCharges, debido a su baja significancia estadística.

La comparación mediante un análisis de devianza mostró que la diferencia entre ambos modelos no es estadísticamente significativa (p = 0.9917). Esto indica que la eliminación de dichas variables no afecta de manera importante la capacidad explicativa del modelo.

Por esta razón, se seleccionó el modelo reducido como modelo final, ya que presenta una estructura más simple y mantiene un nivel de ajuste equivalente al modelo más complejo.

#——————————————————————————# # 7. Evaluación del modelo #——————————————————————————# #——————————————————————————# # 7.1. Predicciones y matriz de clasificación #——————————————————————————#

# 7.1 - Predicciones y matriz de clasificación
prob <- predict(mod3, type = "response")

pred <- ifelse(prob > 0.5, "Yes", "No")

pred <- factor(pred, levels = c("No", "Yes"))

matriz <- table(Predicho = pred,
                Real = datos$Churn)

matriz
##         Real
## Predicho   No  Yes
##      No  4634  856
##      Yes  529 1013

#——————————————————————————# # 7.2 Accuracy, Sensibilidad y Especificidad #——————————————————————————#

# Paso 7.2 - Métricas de desempeño

accuracy <- (4634 + 1013) / sum(matriz)

sensibilidad <- 1013 / (1013 + 856)

especificidad <- 4634 / (4634 + 529)

accuracy
## [1] 0.8030432
sensibilidad
## [1] 0.5420011
especificidad
## [1] 0.8975402

7. Evaluación del modelo

El desempeño del modelo fue evaluado mediante una matriz de clasificación y las métricas de accuracy, sensibilidad y especificidad.

Los resultados muestran una exactitud (accuracy) de 80.30%, indicando que el modelo clasifica correctamente aproximadamente ocho de cada diez clientes. La sensibilidad fue de 54.20%, lo que significa que el modelo logra identificar poco más de la mitad de los clientes que efectivamente abandonan el servicio. Por su parte, la especificidad alcanzó un valor de 89.75%, evidenciando una alta capacidad para reconocer correctamente a los clientes que permanecen en la compañía.

En conjunto, estos resultados indican que el modelo presenta un buen desempeño general y una elevada capacidad para identificar clientes que continúan utilizando los servicios de la empresa, aunque existe margen de mejora en la detección de clientes con riesgo de abandono.

#——————————————————————————# # 8. Conclusiones #——————————————————————————# 1. El análisis exploratorio permitió identificar que el abandono de clientes no se distribuye de manera uniforme dentro de la población estudiada. Aproximadamente el 26.58% de los clientes cancelaron el servicio, evidenciando que la retención de usuarios constituye un aspecto relevante para la compañía.

  1. Las variables asociadas con la permanencia del cliente fueron las que mostraron una mayor capacidad explicativa. En particular, la antigüedad del cliente (tenure) y el tipo de contrato presentaron una fuerte relación con el abandono, observándose menores tasas de cancelación entre los clientes con contratos de largo plazo y mayor tiempo de permanencia.

  2. Factores relacionados con los servicios contratados también influyen en el comportamiento de los usuarios. Los clientes con servicio de internet por fibra óptica, sin soporte técnico y con pago mediante Electronic Check presentaron mayores niveles de abandono en comparación con otros grupos.

  3. El modelo de regresión logística desarrollado alcanzó una exactitud del 80.30%, mostrando una adecuada capacidad para clasificar el comportamiento de los clientes. Los resultados obtenidos demuestran que las técnicas de análisis de datos y modelado predictivo pueden constituir una herramienta útil para identificar usuarios con riesgo de abandono y apoyar estrategias de retención.

En términos generales, los resultados obtenidos evidencian el potencial de las técnicas de análisis de datos para comprender el comportamiento de los clientes y apoyar la toma de decisiones en estrategias de retención. La metodología empleada permitió identificar variables clave asociadas al abandono y construir un modelo con capacidad predictiva adecuada para este tipo de problema.