Customer Churn Prediction Using ANN with TensorFlow in Python
In this tutorial, we will discuss customer churn prediction using ANN with TensorFlow deep learning Python module. We will use Keras API built on top of TensorFlow
ANN:-Artificial Neural Networks.
Churn tells you how many existing customers are leaving your business, so lowering churn has a big positive impact on your revenue streams. Churn is a good indicator of growth potential.
You can download the data set from here Customer churn dataset.
So let’s try to implement the code
Import the necessary Python libraries.
import pandas as pd from matplotlib import pyplot as plt import numpy as np import tensorflow as tf from tensorflow import keras %matplotlib inline
The first step is Data Collection,
1. Load data
c_churn=pd.read_csv("C:\\Users\\usersdrive\\OneDrive\\Desktop\\Customer churn dataset.csv")
To check whether the data set is loaded or not print the first five rows by using the head method.
c_churn.head()
OUTPUT:
Now print the last five rows by using the tail method.
c_churn.tail()
OUTPUT:
Remember this point whenever u are working on machine learning problems that need data exploration.
For churn prediction, the customer id column is not useful so remove the 1 st column.
c_churn.drop('customerID',axis='columns',inplace=True)
To check whether the column is dropped or not.
c_churn.dtypes
OUTPUT:
By seeing the above output the customer id column is dropped successfully.
The customer will be moved out because of the high total charges values or monthly charges.
let’s convert it into float variables.
The monthly charges are in float, the total charges are in an object.
c_churn.TotalCharges.values
OUTPUT:
array(['29.85', '1889.5', '108.15', ..., '346.45', '306.6', '6844.5'], dtype=object)
Values are in string format.
Checking the monthly charges
c_churn.MonthlyCharges.values
OUTPUT:
array([ 29.85, 56.95, 53.85, ..., 29.6 , 74.4 , 105.65])
To change into the float first need to check a null value is present in the dataset.
To check null values.
pd.to_numeric(c_churn.TotalCharges,errors='coerce').isnull() #means if errors is present then it will fill up with some values
OUTPUT:
To check any null variables present in the dataset.
c_churn[pd.to_numeric(c_churn.TotalCharges,errors='coerce').isnull()]
OUTPUT:
In the dataset, there is a total of 11 rows that are null in the total charges column.
If the null values are present in the dataset then the accuracy will not predict correctly.
It’s better to remove the null values.
To check the dataset size.
c_churn.shape
OUTPUT:
(7043, 20)
Need to check which columns are present in the dataset.
c_churn.iloc[488]
OUTPUT:
Remove the 11 rows in which the null values are present.
df1=c_churn[c_churn.TotalCharges!=' '] df1.shape
OUTPUT:
(7032, 20)
To check which variables are present in df1.
OUTPUT:
The Total charges are in the object to change into the float using the numeric function.
pd.to_numeric(df1.TotalCharges)
OUTPUT:
To check the total charges in which datatype.
df1.TotalCharges.dtypes
OUTPUT:
dtype('Float')
The second step is
DATA VISUALIZATION
Visualize in the form of a histogram graph.
#lets do the graph for the customers no of tenure tenure_churn_no=df1[df1.Churn=='No'].tenure tenure_churn_yes=df1[df1.Churn=='Yes'].tenure plt.xlabel('tenure') plt.ylabel("Number of customers") plt.title("Customer Churn Prediction Visualization") plt.hist([tenure_churn_yes,tenure_churn_no],label=['churn=Yes','churn=No']) plt.legend()
OUTPUT:
The above histogram is for tenure.
Now can check for total charges.
mc_churn_no=df1[df1.Churn=='No'].MonthlyCharges mc_churn_yes=df1[df1.Churn=='Yes'].MonthlyCharges plt.xlabel('Monthly Charges') plt.ylabel("Number of customers") plt.title("Customer Churn Prediction Visualization") plt.hist([mc_churn_yes,mc_churn_no],label=['churn=Yes','churn=No'],color=['Green','red']) plt.legend()
OUTPUT:
By seeing the above output we can analyze the company is in trouble.
The machines will not understand the binary values so change the variables into binary.
LABEL ENCODING
def print_unique_col_values(c_churn): for column in c_churn: if c_churn[column].dtypes=='object': print(f'{column} : {c_churn[column].unique()}')
Change into the binary values.
df1.replace('No internet service','No',inplace=True) df1.replace('No phone service','No',inplace=True)
print_unique_col_values(df1)
OUTPUT:
Now change the remaining columns with the 0 or 1 binary values.
yes_no_columns=['Partner','Dependents','PhoneService','MultipleLines','OnlineSecurity','OnlineBackup','DeviceProtection', 'TechSupport','StreamingTV','StreamingMovies','PaperlessBilling','Churn'] for col in yes_no_columns: df1[col].replace({'Yes': 1,'No': 0},inplace=True)
for col in df1: print(f'{col}: {df1[col].unique()}')
OUTPUT:
Replace male and female with 0 and 1.
df1['gender'].replace({'Female':1,'Male':0},inplace=True)
df1['gender'].unique()
OUTPUT:
array([1, 0], dtype=int64)
But still, in the contract function there are three types of variables then use the panda’s dummy function.
#in case of contract function there is 3 objects thats why we use dummy fuctions in pandas df2=pd.get_dummies(data=df1,columns=['InternetService','Contract','PaymentMethod']) df2.columns
OUTPUT:
Now all the column values are in binary values lest check with the code.
df2.sample(4)
OUTPUT:
Now all are in either integer or float type.
df2.dtypes
OUTPUT:
SCALING STEP
For three columns that are not present in binary values to get binary values, we need to do the scaling.
cols_to_scale=['tenure','MonthlyCharges','TotalCharges'] from sklearn.preprocessing import MinMaxScaler scaler=MinMaxScaler() df2[cols_to_scale]=scaler.fit_transform(df2[cols_to_scale])
To check the data
df2.sample(3)
OUTPUT:
To check the unique values.
for col in df2: print(f'{col}: {df2[col].unique()}')
OUTPUT:
Now the full dataset is in binary form
Now implement the test and train data.
X=df2.drop('Churn',axis='columns') y=df2['Churn']
from sklearn.model_selection import train_test_split X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=5)
X_train.shape
OUTPUT:
(5625, 26)
Let’s check the test dataset.
X_test.shape
OUTPUT:
(1407, 26)
Let’s check the variables in the train.
X_train[:10]
OUTPUT:
Checking the length of the training dataset.
len(X_train.columns)
OUTPUT:
26
MODEL EVALUATION
import tensorflow as tf from tensorflow import keras model=keras.Sequential([ keras.layers.Dense(26,input_shape=(26,),activation='relu'), keras.layers.Dense(1,activation='sigmoid'), ]) model.compile(optimizer='adam',loss='binary_crossentropy',metrics=['accuracy']) model.fit(X_train,y_train,epochs=100)
OUTPUT:
The accuracy is 82 percent which is good.
Evaluation of model.
model.evaluate(X_test,y_test)
OUTPUT:
44/44 [==============================] - 0s 823us/step - loss: 0.4590 - accuracy: 0.7775 [0.4590034484863281, 0.7775408625602722]
To check the array values.
yp=model.predict(X_test) yp[:5]
OUTPUT:
44/44 [==============================] - 0s 848us/step array([[0.14974326], [0.36690223], [0.00675797], [0.80207884], [0.40584573]], dtype=float32)
The array is in the 2-dimensional format and needs to change to the 1-dimensional format.
y_test[:10]
OUTPUT:
Convert 2d addy into 1 d array.
y_pred=[] for element in yp: if element > 0.5: y_pred.append(1) else: y_pred.append(0)
y_pred[:10]
OUTPUT:
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0]
Need to check the classification reports.
from sklearn.metrics import confusion_matrix,classification_report print(classification_report(y_test,y_pred))
OUTPUT:
Lets crosscheck with the heatmap.
import seaborn as sn cm=tf.math.confusion_matrix(labels=y_test,predictions=y_pred) plt.figure(figsize=(10,10)) sn.heatmap(cm,annot=True,fmt='d') plt.xlabel('Predicted') plt.ylabel('Truth')
OUTPUT:
Diagnolas are correct predictions and non diagnoals are not correct predictions.
Accuracy
round((862+229)/(862+229+137+179),2)
OUTPUT:
0.78
precision for 0 th class
round(862/(862+179),2)
OUTPUT:
0.83
precision for 1 class precision for customers who are actually churned.
round(229/(229+137),2)
OUTPUT:
0.63
Recall for 0 th class.
round(862/(862+137),2)
OUTPUT:
0.86
round(229/(229+179),2)
OUTPUT:
0.56
Leave a Reply