Predicción de Churn de clientes en telecomunicaciones
PREDECIR EL COMPORTAMIENTO PARA RETENER A LOS CLIENTES DE TELECOMUNICACIONES
Predecir el comportamiento para retener a los clientes. Puede analizar todos los datos relevantes de los clientes y desarrollar programas de retención de clientes enfocados Cada fila representa un cliente, cada columna contiene los atributos del cliente descritos en la columna Metadatos.
El conjunto de datos incluye información sobre:
- Clientes que se fueron en el último mes: la columna se llama Rotación
- Servicios a los que se ha registrado cada cliente: teléfono, líneas múltiples, Internet, seguridad en línea, respaldo en línea, protección de dispositivos, soporte técnico y transmisión de TV y películas.
- Información de la cuenta del cliente: cuánto tiempo ha sido cliente, contrato, método de pago, facturación electrónica, cargos mensuales y cargos totales.
- Información demográfica sobre los clientes: sexo, rango de edad y si tienen parejas y dependientes.
1!pip install --upgrade scikit-learn
2!pip install scikit-learn # librerias necesarias
3import numpy as np
4import pandas as pd
5import matplotlib.pyplot as plt
6import seaborn as sns
7from sklearn.linear_model import LogisticRegression
8from sklearn.model_selection import train_test_split
9from sklearn.metrics import confusion_matrix
10from sklearn.preprocessing import MinMaxScaler
11from sklearn import metrics
12from sklearn.metrics import classification_report # Traemos el archivo, el cual esta alojado en drive
13from google.colab import drive
14
15# Montar Drive
16drive.mount('/content/drive')
17# Ruta del archivo
18ruta_archivo = '/content/drive/My Drive/db/Telco-Customer-Churn.csv'
19# Guardamos el archivo
20df = pd.read_csv(ruta_archivo)
1# Aplicamos la limpieza a los datos
2
3# Cambiamos totalCharges a valores numericos
4df.TotalCharges = pd.to_numeric(df.TotalCharges, errors = 'coerce')
5
6# Mostramos los valores nulos
7print(df.isnull().sum())
8
9# Eliminamos los valores nulos
10df.dropna(inplace = True)
11
12# mostramos los valores nullos nuevamente
13df.isnull().sum()
14
15# Eliminamos la columna ID que no hace nada
16df.drop('customerID', axis = 1, inplace = True)
17
18# Pasamos nuestra variable dependiente que es categórica a variable binaria
19df['Churn'].replace(to_replace= 'Yes', value = 1, inplace = True)
20df['Churn'].replace(to_replace= 'No', value = 0, inplace = True)
21
22# Hacemos un backup para no dañar el dataset original
23df_processing = df.copy()
24
25# Pasamos nuestras variables independientes que están en categóricas a numéricas (One-Hot Encoding)
26df_processing = pd.get_dummies(df_processing)
1# Vamos a realizar el análisis de correlación para determinar la multicolinealidad
2fig = plt.figure(figsize = (15, 6))
3df_processing.corr()['Churn'].sort_values(ascending = True).plot(kind = 'bar')
4plt.show()
1# Ahora vamos a normalizar los datos, llevarlos a la misma escala
2scaler = MinMaxScaler()
3
4# Aplicamos la escalabilidad
5df_processing_norm = pd.DataFrame(scaler.fit_transform(df_processing)) # Observamos nuestros nuevos datos
6df_processing_norm.head()
7
8# Como los nombres se perdieron, vamos a volver a ponerlos
9
10# Sacamos los nombres originales
11columns = df_processing.columns
12
13# Se los ponemos al DataFrame nuevo
14df_processing_norm.columns = columns
15
16# Imprimimos las 10 primeras filas
17df_processing_norm.head(10)
1# Ahora vamos a realizar el análisis exploratorio
2
3# Primero creamos una función para graficar las variables categóricas
4def painChart(column):
5 fig = plt.figure(figsize = (5, 5))
6 sns.countplot(df, x = column, hue = 'Churn')
7 plt.show()
8
9# Ahora sacamos los nombres de las variables que son categóricas
10names = df.select_dtypes(include = 'object').columns
1# Analizamos ahora los datos numéricos
2sns.pairplot(df, hue = 'Churn')
3plt.show()
1# Separamos nuestros datos en x y y
2x = df_processing_norm.drop('Churn', axis = 1)
3y = df_processing_norm['Churn'].values
4
5# Separamos en entrenamiento y test
6x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.3, random_state = 42)
7
8# Guardamos el modelo
9model = LogisticRegression()
10
11# Entrenamos el modelo
12model.fit(x_train, y_train)
13
14# Creamos la predicción con los datos de test
15prediction = model.predict(x_test)
16
17# Evaluamos la precisión de nuestro modelo
18accuracy = metrics.accuracy_score(y_test, prediction)
19accuracy_perc = round(accuracy * 100, 3)
20print('Nivel de precisión: ', accuracy_perc, '%')
Nivel de precision: 79.526 %
1# Evaluamos los datos predichos con los datos de y_test, para ver su rendimiento
2# Creamos una matriz de confusión para ver los verdaderos positivos y los falsos positivos
3cm = confusion_matrix(prediction, y_test, labels=model.classes_)
4
5# Ahora vamos a evaluar el modelo
6
7# Obtenemos las probabilidades de los eventos, es decir, las probabilidades de que una fila de datos sea clase 0 o clase 1
8probs = model.predict_proba(x_test)
9# Ejemplo de salida: array([[0.99, 0.01], [0.86, 0.14], ..., [0.70, 0.30]])
10
11# Observamos los coeficientes del modelo
12# Valores positivos indican mayor influencia hacia la clase 1 (Churn)
13# Valores negativos indican mayor influencia hacia la clase 0 (No Churn)
14coefs = model.coef_
1# Vemos los nombres de los features al detalle
2feature_names = model.feature_names_in_
3
4# ['SeniorCitizen', 'tenure', 'MonthlyCharges', 'TotalCharges',
5# 'gender_Female', 'gender_Male', 'Partner_No', 'Partner_Yes',
6# 'Dependents_No', 'Dependents_Yes', 'PhoneService_No',
7# 'PhoneService_Yes', 'MultipleLines_No',
8# 'MultipleLines_No phone service', 'MultipleLines_Yes',
9# 'InternetService_DSL', 'InternetService_Fiber optic',
10# 'InternetService_No', 'OnlineSecurity_No',
11# 'OnlineSecurity_No internet service', 'OnlineSecurity_Yes',
12# 'OnlineBackup_No', 'OnlineBackup_No internet service',
13# 'OnlineBackup_Yes', 'DeviceProtection_No',
14# 'DeviceProtection_No internet service', 'DeviceProtection_Yes',
15# 'TechSupport_No', 'TechSupport_No internet service',
16# 'TechSupport_Yes', 'StreamingTV_No',
17# 'StreamingTV_No internet service', 'StreamingTV_Yes',
18# 'StreamingMovies_No', 'StreamingMovies_No internet service',
19# 'StreamingMovies_Yes', 'Contract_Month-to-month',
20# 'Contract_One year', 'Contract_Two year', 'PaperlessBilling_No',
21# 'PaperlessBilling_Yes', 'PaymentMethod_Bank transfer (automatic)',
22# 'PaymentMethod_Credit card (automatic)',
23# 'PaymentMethod_Electronic check', 'PaymentMethod_Mailed check']
1# Creamos una grafica relacionando los featurs_name con los coef
2weights = pd.Series(model.coef_[0], index = x.columns.values)
3
4# Creamos el grafico con los primeros 10 coeficientes que tienen más inferencia en que el resultado sea 1
5print(weights.sort_values(ascending=False)[:10].plot(kind='bar'))
1# Ahora vemos los que tienen más relevancia para que el resultado sea 0
2print(wwights.sort_values(ascending=False)[-10:].plot(kind='bar'))
EVALUACIÓN DEL MODELO
A partir de la matriz de confusión, es evidente que nuestro modelo no está equilibrado. Existe una mayor cantidad de datos para la clasificación ‘0’ en comparación con la clasificación ‘1’, lo que disminuye el nivel de precisión. Además, se identifica que algunos atributos no contribuyen significativamente a la probabilidad de que un resultado sea clasificado como ‘1’ o ‘0’. Por lo tanto, es necesario realizar una limpieza de estos atributos que no aportan a la predicción de la probabilidad de los eventos. A continuación, procederemos a realizar las correcciones pertinentes
1# Observamos el balance de los datos categoricos
2print((df['Churn'].value_counts(normalize = True)*100).round(3))
3print('Observamos el desequilibrio por lo que nuestro accuracy no es tan bueno')
| 0 => 73.422. 1 => 26.578 | Observamos el desequilibrio por lo que nuestro accuracy no es tan bueno
1# Observamos el accuracy, recall y f1-score por categoria, y el total
2predictionEvaluation = prediction.reshape(-1, 1)
3print(classification_report(y_test, predictionEvaluation))
4print('Podemos observar el desequilibrio entre las categorias')
| precision recall f1-score support
0.0 0.84 0.89 0.86 1549
1.0 0.64 0.53 0.58 561
accuracy 0.80 2110
macro avg 0.74 0.71 0.72 2110
weighted avg 0.79 0.80 0.79 2110
Podemos observar el desequilibrio entre las categorias
1# Ahora vamos a balancear las clases
2from sklearn.utils import resample
3
4# Separamos las clases
5df_major = df_processing_norm[df_processing_norm['Churn'] == 0]
6df_minor = df_processing_norm[df_processing_norm['Churn'] == 1]
7
8# Aplicamos el resampling
9df_major_upsampled = resample(df_major,
10 replace=True, # Muestreo con reemplazo
11 n_samples=len(df_minor), # Para igualar la clase mayoritaria
12 random_state=123) # Para reproducibilidad
13
14# Combinamos la clase mayoritaria con la clase minoritaria aumentada
15df_balanced = pd.concat([df_minor, df_major_upsampled])
16
17# Mostramos el número de observaciones por clase
18df_balanced['Churn'].value_counts() # 1.0 1869
19# 0.0 1869
1# Eliminamos los features que no son relevante para el modelo
2df_balanced = df_balanced.drop([
3 'gender_Female', 'gender_Male', 'MultipleLines_No',
4 'MultipleLines_No phone service', 'MultipleLines_Yes', 'PhoneService_No',
5 'PhoneService_Yes', 'StreamingMovies_No', 'StreamingMovies_No internet service',
6 'StreamingMovies_Yes', 'StreamingTV_No', 'StreamingTV_No internet service',
7 'StreamingTV_Yes'
8], axis=1)
9
10# Ahora creamos el modelo con los nuevos datos
11# Separamos nuestros datos en x y y
12x2 = df_balanced.drop('Churn', axis=1)
13y2 = df_balanced['Churn'].values
14
15# Separamos en entrenamiento y test
16x_train2, x_test2, y_train2, y_test2 = train_test_split(x2, y2, test_size=0.3, random_state=42)
17
18# Guardamos el modelo
19model2 = LogisticRegression()
20
21# Entrenamos el modelo
22model2.fit(x_train2, y_train2)
23
24# Creamos la predicción con los datos de test
25prediction2 = model2.predict(x_test2)
26
27# Evaluamos el rendimiento del modelo
28print(classification_report(y_test2, prediction2))
| precision recall f1-score support
0.0 0.76 0.73 0.75 544
1.0 0.76 0.79 0.77 578
accuracy 0.76 1122
macro avg 0.76 0.76 0.76 1122
weighted avg 0.76 0.76 0.76 1122
1# Evaluamos la precisión de nuestro modelo
2accuracy2 = metrics.accuracy_score(y_test2, prediction2)
3accuracy_perc = round(accuracy2 * 100, 3)
4print('Nivel de precisión: ', accuracy_perc, '%')
Nivel de precision: 75.936 %
1# Evaluamos los datos predichos con los datos de y_test, para ver su rendimiento
2# Creamos una matriz de confusión para ver los verdaderos positivos y los falsos positivos
3cm2 = confusion_matrix(prediction2, y_test2, labels = model2.classes_)
| [[398 124]
[146 454]]
Explora el Proyecto
Contenido Relacionado
Predicción de la pérdida de clientes mediante aprendizaje automático
La predicción de la pérdida de clientes predice la probabilidad de que los clientes cancelen los productos o servicios de una empresa.
REGRESIÓN LOGÍSTICA. CURSO COMPLETO
Curso completo de regresión logística binaria y multinomial en SPSS. Todos los análisis y la forma de realizarlo, interpretarlo y reportarlo en tu informe de investigación.
Comentarios
Cargando comentarios...