Inserting Required Files¶

In [2]:
#Inserting the files needed
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

#Implementing required algorithms
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score, roc_curve
from sklearn.metrics import roc_curve, roc_auc_score
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from sklearn.svm import SVC
from sklearn.metrics import classification_report, confusion_matrix

Allowing Python to Read Excel Dataset¶

In [4]:
df = pd.read_excel('Telco_Customer_Churn.xlsx')

Display Top 15 Lines¶

In [6]:
#Understanding the data by displaying top 15 lines within the database

df.head(15)
Out[6]:
CustomerID Count Country State City Zip Code Lat Long Latitude Longitude Gender ... Contract Paperless Billing Payment Method Monthly Charges Total Charges Churn Label Churn Value Churn Score CLTV Churn Reason
0 3668-QPYBK 1 United States California Los Angeles 90003 33.964131, -118.272783 33.964131 -118.272783 Male ... Month-to-month Yes Mailed check 53.85 108.15 Yes 1 86 3239 Competitor made better offer
1 9237-HQITU 1 United States California Los Angeles 90005 34.059281, -118.30742 34.059281 -118.307420 Female ... Month-to-month Yes Electronic check 70.70 151.65 Yes 1 67 2701 Moved
2 9305-CDSKC 1 United States California Los Angeles 90006 34.048013, -118.293953 34.048013 -118.293953 Female ... Month-to-month Yes Electronic check 99.65 820.5 Yes 1 86 5372 Moved
3 7892-POOKP 1 United States California Los Angeles 90010 34.062125, -118.315709 34.062125 -118.315709 Female ... Month-to-month Yes Electronic check 104.80 3046.05 Yes 1 84 5003 Moved
4 0280-XJGEX 1 United States California Los Angeles 90015 34.039224, -118.266293 34.039224 -118.266293 Male ... Month-to-month Yes Bank transfer (automatic) 103.70 5036.3 Yes 1 89 5340 Competitor had better devices
5 4190-MFLUW 1 United States California Los Angeles 90020 34.066367, -118.309868 34.066367 -118.309868 Female ... Month-to-month No Credit card (automatic) 55.20 528.35 Yes 1 78 5925 Competitor offered higher download speeds
6 8779-QRDMV 1 United States California Los Angeles 90022 34.02381, -118.156582 34.023810 -118.156582 Male ... Month-to-month Yes Electronic check 39.65 39.65 Yes 1 100 5433 Competitor offered more data
7 1066-JKSGK 1 United States California Los Angeles 90024 34.066303, -118.435479 34.066303 -118.435479 Male ... Month-to-month No Mailed check 20.15 20.15 Yes 1 92 4832 Competitor made better offer
8 6467-CHFZW 1 United States California Los Angeles 90028 34.099869, -118.326843 34.099869 -118.326843 Male ... Month-to-month Yes Electronic check 99.35 4749.15 Yes 1 77 5789 Competitor had better devices
9 8665-UTDHZ 1 United States California Los Angeles 90029 34.089953, -118.294824 34.089953 -118.294824 Male ... Month-to-month No Electronic check 30.20 30.2 Yes 1 97 2915 Competitor had better devices
10 8773-HHUOZ 1 United States California Los Angeles 90032 34.078821, -118.177576 34.078821 -118.177576 Female ... Month-to-month Yes Mailed check 64.70 1093.1 Yes 1 74 3022 Competitor offered higher download speeds
11 6047-YHPVI 1 United States California Los Angeles 90039 34.110845, -118.259595 34.110845 -118.259595 Male ... Month-to-month Yes Electronic check 69.70 316.9 Yes 1 66 2454 Competitor offered higher download speeds
12 5380-WJKOV 1 United States California Los Angeles 90041 34.137412, -118.207607 34.137412 -118.207607 Male ... Month-to-month Yes Electronic check 106.35 3549.25 Yes 1 65 2941 Competitor offered higher download speeds
13 8168-UQWWF 1 United States California Los Angeles 90042 34.11572, -118.192754 34.115720 -118.192754 Female ... Month-to-month Yes Bank transfer (automatic) 97.85 1105.4 Yes 1 70 5674 Competitor offered more data
14 7760-OYPDY 1 United States California Los Angeles 90056 33.987945, -118.370442 33.987945 -118.370442 Female ... Month-to-month Yes Electronic check 80.65 144.15 Yes 1 90 5586 Competitor offered more data

15 rows × 33 columns

Display Bottom 15 Lines¶

In [9]:
#Understanding the data by displaying the bottom 15 lines of the data 

df.tail(15)
Out[9]:
CustomerID Count Country State City Zip Code Lat Long Latitude Longitude Gender ... Contract Paperless Billing Payment Method Monthly Charges Total Charges Churn Label Churn Value Churn Score CLTV Churn Reason
7028 7398-LXGYX 1 United States California Pioneertown 92268 34.201108, -116.593456 34.201108 -116.593456 Male ... Month-to-month Yes Credit card (automatic) 84.80 3626.35 No 0 44 2770 NaN
7029 2823-LKABH 1 United States California Rancho Mirage 92270 33.763678, -116.429928 33.763678 -116.429928 Female ... Month-to-month Yes Bank transfer (automatic) 95.05 1679.4 No 0 60 4524 NaN
7030 0550-DCXLH 1 United States California Thermal 92274 33.53604, -116.119222 33.536040 -116.119222 Male ... Month-to-month No Mailed check 73.35 931.55 No 0 65 4645 NaN
7031 9281-CEDRU 1 United States California Salton City 92275 33.28156, -115.955541 33.281560 -115.955541 Female ... Two year No Bank transfer (automatic) 64.10 4326.25 No 0 48 5553 NaN
7032 2235-DWLJU 1 United States California Thousand Palms 92276 33.849263, -116.382778 33.849263 -116.382778 Female ... Month-to-month Yes Electronic check 44.40 263.05 No 0 71 4611 NaN
7033 0871-OPBXW 1 United States California Twentynine Palms 92277 34.17211, -115.769773 34.172110 -115.769773 Female ... Month-to-month Yes Mailed check 20.05 39.25 No 0 80 5191 NaN
7034 3605-JISKB 1 United States California Twentynine Palms 92278 34.457829, -116.139589 34.457829 -116.139589 Male ... One year No Credit card (automatic) 60.00 3316.1 No 0 71 4212 NaN
7035 9767-FFLEM 1 United States California Westmorland 92281 33.03679, -115.60503 33.036790 -115.605030 Male ... Month-to-month Yes Credit card (automatic) 69.50 2625.25 No 0 35 4591 NaN
7036 8456-QDAVC 1 United States California Winterhaven 92283 32.852947, -114.850784 32.852947 -114.850784 Male ... Month-to-month Yes Bank transfer (automatic) 78.70 1495.1 No 0 20 2464 NaN
7037 7750-EYXWZ 1 United States California Yucca Valley 92284 34.159534, -116.425984 34.159534 -116.425984 Female ... One year No Electronic check 60.65 743.3 No 0 24 3740 NaN
7038 2569-WGERO 1 United States California Landers 92285 34.341737, -116.539416 34.341737 -116.539416 Female ... Two year Yes Bank transfer (automatic) 21.15 1419.4 No 0 45 5306 NaN
7039 6840-RESVB 1 United States California Adelanto 92301 34.667815, -117.536183 34.667815 -117.536183 Male ... One year Yes Mailed check 84.80 1990.5 No 0 59 2140 NaN
7040 2234-XADUH 1 United States California Amboy 92304 34.559882, -115.637164 34.559882 -115.637164 Female ... One year Yes Credit card (automatic) 103.20 7362.9 No 0 71 5560 NaN
7041 4801-JZAZL 1 United States California Angelus Oaks 92305 34.1678, -116.86433 34.167800 -116.864330 Female ... Month-to-month Yes Electronic check 29.60 346.45 No 0 59 2793 NaN
7042 3186-AJIEK 1 United States California Apple Valley 92308 34.424926, -117.184503 34.424926 -117.184503 Male ... Two year Yes Bank transfer (automatic) 105.65 6844.5 No 0 38 5097 NaN

15 rows × 33 columns

Description Of Data¶

In [11]:
df.describe()
Out[11]:
Count Zip Code Latitude Longitude Tenure Months Monthly Charges Churn Value Churn Score CLTV
count 7043.0 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000 7043.000000
mean 1.0 93521.964646 36.282441 -119.798880 32.371149 64.761692 0.265370 58.699418 4400.295755
std 0.0 1865.794555 2.455723 2.157889 24.559481 30.090047 0.441561 21.525131 1183.057152
min 1.0 90001.000000 32.555828 -124.301372 0.000000 18.250000 0.000000 5.000000 2003.000000
25% 1.0 92102.000000 34.030915 -121.815412 9.000000 35.500000 0.000000 40.000000 3469.000000
50% 1.0 93552.000000 36.391777 -119.730885 29.000000 70.350000 0.000000 61.000000 4527.000000
75% 1.0 95351.000000 38.224869 -118.043237 55.000000 89.850000 1.000000 75.000000 5380.500000
max 1.0 96161.000000 41.962127 -114.192901 72.000000 118.750000 1.000000 100.000000 6500.000000

Summary Of Data¶

In [13]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7043 entries, 0 to 7042
Data columns (total 33 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   CustomerID         7043 non-null   object 
 1   Count              7043 non-null   int64  
 2   Country            7043 non-null   object 
 3   State              7043 non-null   object 
 4   City               7043 non-null   object 
 5   Zip Code           7043 non-null   int64  
 6   Lat Long           7043 non-null   object 
 7   Latitude           7043 non-null   float64
 8   Longitude          7043 non-null   float64
 9   Gender             7043 non-null   object 
 10  Senior Citizen     7043 non-null   object 
 11  Partner            7043 non-null   object 
 12  Dependents         7043 non-null   object 
 13  Tenure Months      7043 non-null   int64  
 14  Phone Service      7043 non-null   object 
 15  Multiple Lines     7043 non-null   object 
 16  Internet Service   7043 non-null   object 
 17  Online Security    7043 non-null   object 
 18  Online Backup      7043 non-null   object 
 19  Device Protection  7043 non-null   object 
 20  Tech Support       7043 non-null   object 
 21  Streaming TV       7043 non-null   object 
 22  Streaming Movies   7043 non-null   object 
 23  Contract           7043 non-null   object 
 24  Paperless Billing  7043 non-null   object 
 25  Payment Method     7043 non-null   object 
 26  Monthly Charges    7043 non-null   float64
 27  Total Charges      7043 non-null   object 
 28  Churn Label        7043 non-null   object 
 29  Churn Value        7043 non-null   int64  
 30  Churn Score        7043 non-null   int64  
 31  CLTV               7043 non-null   int64  
 32  Churn Reason       1869 non-null   object 
dtypes: float64(3), int64(6), object(24)
memory usage: 1.8+ MB

Identify Unique Values¶

In [15]:
df.nunique()
Out[15]:
CustomerID           7043
Count                   1
Country                 1
State                   1
City                 1129
Zip Code             1652
Lat Long             1652
Latitude             1652
Longitude            1651
Gender                  2
Senior Citizen          2
Partner                 2
Dependents              2
Tenure Months          73
Phone Service           2
Multiple Lines          3
Internet Service        3
Online Security         3
Online Backup           3
Device Protection       3
Tech Support            3
Streaming TV            3
Streaming Movies        3
Contract                3
Paperless Billing       2
Payment Method          4
Monthly Charges      1585
Total Charges        6531
Churn Label             2
Churn Value             2
Churn Score            85
CLTV                 3438
Churn Reason           20
dtype: int64

Idenitfying and Organising Numerical Columns¶

In [17]:
print(df.columns)
Index(['CustomerID', 'Count', 'Country', 'State', 'City', 'Zip Code',
       'Lat Long', 'Latitude', 'Longitude', 'Gender', 'Senior Citizen',
       'Partner', 'Dependents', 'Tenure Months', 'Phone Service',
       'Multiple Lines', 'Internet Service', 'Online Security',
       'Online Backup', 'Device Protection', 'Tech Support', 'Streaming TV',
       'Streaming Movies', 'Contract', 'Paperless Billing', 'Payment Method',
       'Monthly Charges', 'Total Charges', 'Churn Label', 'Churn Value',
       'Churn Score', 'CLTV', 'Churn Reason'],
      dtype='object')
In [18]:
numerical_columns=['Tenure Months','Monthly Charges','Total Charges','Churn Value','Churn Score','CLTV']
In [19]:
df[numerical_columns].describe().T
Out[19]:
count mean std min 25% 50% 75% max
Tenure Months 7043.0 32.371149 24.559481 0.00 9.0 29.00 55.00 72.00
Monthly Charges 7043.0 64.761692 30.090047 18.25 35.5 70.35 89.85 118.75
Churn Value 7043.0 0.265370 0.441561 0.00 0.0 0.00 1.00 1.00
Churn Score 7043.0 58.699418 21.525131 5.00 40.0 61.00 75.00 100.00
CLTV 7043.0 4400.295755 1183.057152 2003.00 3469.0 4527.00 5380.50 6500.00
In [20]:
df[numerical_columns].hist(figsize=(15,15))
plt.show()
No description has been provided for this image

Identify and Organising Categorical Columns¶

In [32]:
categorical_columns=['City','Gender','Senior Citizen','Partner','Dependents','Phone Service','Multiple Lines',
          'Internet Service','Online Security','Online Backup','Device Protection','Tech Support','Streaming TV','Streaming Movies',
          'Contract','Paperless Billing','Payment Method','Churn Label', 'Churn Reason']
In [34]:
df[categorical_columns].describe().T
Out[34]:
count unique top freq
City 7043 1129 Los Angeles 305
Gender 7043 2 Male 3555
Senior Citizen 7043 2 No 5901
Partner 7043 2 No 3641
Dependents 7043 2 No 5416
Phone Service 7043 2 Yes 6361
Multiple Lines 7043 3 No 3390
Internet Service 7043 3 Fiber optic 3096
Online Security 7043 3 No 3498
Online Backup 7043 3 No 3088
Device Protection 7043 3 No 3095
Tech Support 7043 3 No 3473
Streaming TV 7043 3 No 2810
Streaming Movies 7043 3 No 2785
Contract 7043 3 Month-to-month 3875
Paperless Billing 7043 2 Yes 4171
Payment Method 7043 4 Electronic check 2365
Churn Label 7043 2 No 5174
Churn Reason 1869 20 Attitude of support person 192
In [36]:
for i in categorical_columns:
    print(df[i].value_counts (normalize=True) * 100)
    print('')
City
Los Angeles       4.330541
San Diego         2.129774
San Jose          1.590231
Sacramento        1.533437
San Francisco     1.476643
                    ...   
Healdsburg        0.056794
Jenner            0.056794
Philo             0.056794
Point Arena       0.056794
Olympic Valley    0.056794
Name: proportion, Length: 1129, dtype: float64

Gender
Male      50.47565
Female    49.52435
Name: proportion, dtype: float64

Senior Citizen
No     83.785319
Yes    16.214681
Name: proportion, dtype: float64

Partner
No     51.69672
Yes    48.30328
Name: proportion, dtype: float64

Dependents
No     76.899049
Yes    23.100951
Name: proportion, dtype: float64

Phone Service
Yes    90.316626
No      9.683374
Name: proportion, dtype: float64

Multiple Lines
No                  48.132898
Yes                 42.183729
No phone service     9.683374
Name: proportion, dtype: float64

Internet Service
Fiber optic    43.958540
DSL            34.374556
No             21.666903
Name: proportion, dtype: float64

Online Security
No                     49.666335
Yes                    28.666761
No internet service    21.666903
Name: proportion, dtype: float64

Online Backup
No                     43.844952
Yes                    34.488144
No internet service    21.666903
Name: proportion, dtype: float64

Device Protection
No                     43.944342
Yes                    34.388755
No internet service    21.666903
Name: proportion, dtype: float64

Tech Support
No                     49.311373
Yes                    29.021724
No internet service    21.666903
Name: proportion, dtype: float64

Streaming TV
No                     39.897771
Yes                    38.435326
No internet service    21.666903
Name: proportion, dtype: float64

Streaming Movies
No                     39.542808
Yes                    38.790288
No internet service    21.666903
Name: proportion, dtype: float64

Contract
Month-to-month    55.019168
Two year          24.066449
One year          20.914383
Name: proportion, dtype: float64

Paperless Billing
Yes    59.221922
No     40.778078
Name: proportion, dtype: float64

Payment Method
Electronic check             33.579441
Mailed check                 22.887974
Bank transfer (automatic)    21.922476
Credit card (automatic)      21.610109
Name: proportion, dtype: float64

Churn Label
No     73.463013
Yes    26.536987
Name: proportion, dtype: float64

Churn Reason
Attitude of support person                   10.272873
Competitor offered higher download speeds    10.112360
Competitor offered more data                  8.667737
Don't know                                    8.239700
Competitor made better offer                  7.490637
Attitude of service provider                  7.223114
Competitor had better devices                 6.955591
Network reliability                           5.510968
Product dissatisfaction                       5.457464
Price too high                                5.243446
Service dissatisfaction                       4.761905
Lack of self-service on Website               4.708400
Extra data charges                            3.049759
Moved                                         2.835741
Limited range of services                     2.354200
Long distance charges                         2.354200
Lack of affordable download/upload speed      2.354200
Poor expertise of phone support               1.070091
Poor expertise of online support              1.016586
Deceased                                      0.321027
Name: proportion, dtype: float64

In [618]:
# Ensure this matches your dataset column names
exclude_columns = ['Count', 'Country', 'State', 'CustomerID', 'Lat Long', 'Zip Code', 'Latitude', 'Longitude', 'Churn Reason']

categorical_columns = [
    'Gender', 'Senior Citizen', 'Partner', 'Dependents', 
    'Phone Service', 'Multiple Lines', 'Internet Service', 
    'Online Security', 'Online Backup', 'Device Protection', 
    'Tech Support', 'Streaming TV', 'Streaming Movies', 
    'Contract', 'Paperless Billing', 'Payment Method', 
    'Churn Label'
]

for i in categorical_columns:
    if i != 'Churn Label' and i not in exclude_columns:
        # Crosstab to calculate churn distribution for each category
        data = pd.crosstab(df[i], df['Churn Label'], normalize='index') * 100
        
        # Iterate through each category in the column
        for category in data.index:
            plt.figure(figsize=(8, 6))
            
            # Pie chart
            wedges, texts, autotexts = plt.pie(
                data.loc[category], 
                labels=data.columns, 
                autopct='%1.1f%%', 
                startangle=140
            )
            
            # Adding a key to all graphs
            plt.legend(
                wedges, 
                data.columns, 
                title="Churn Label", 
                loc="best"
            )
            
            # Title on all graphs
            plt.title(f'Relationship between {i} ({category}) and Churn Label')
            plt.show()
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
In [619]:
# Normalize churn distribution across cities
city_churn_data = pd.crosstab(df['City'], df['Churn Label'], normalize='index') * 100

# Plot the stacked bar chart
plt.figure(figsize=(12, 8))
city_churn_data.plot(kind='bar', stacked=True, figsize=(15, 7), colormap='viridis')

# Add labels and title
plt.ylabel('Percentage Churn %')
plt.xlabel('City')
plt.title('Churn Distribution Across Cities')
plt.legend(title='Churn Label', loc='upper right')
plt.tight_layout()
plt.show()
<Figure size 1200x800 with 0 Axes>
No description has been provided for this image
In [620]:
# Checking the relationship between different numerical variables

# Checking for non-numeric values in numerical columns and converting them to NaN

for col in numerical_columns:
    df[col] = pd.to_numeric(df[col], errors='coerce')

# Dropping rows with NaN values in numerical columns

# Plotting the correlation between numerical variables

plt.figure(figsize=(15, 15))
sns.heatmap(df[numerical_columns].corr(), annot=True, fmt='.2f', cmap='YlOrRd')
plt.title('Correlation Matrix of Numerical Variables')
plt.show()
No description has been provided for this image

Data Preparation¶

In [621]:
import pandas as pd

df = pd.read_excel('Telco_customer_churn.xlsx')  # Adjust the file name/path if needed

columns_to_drop = ['CustomerID', 'Lat Long', 'Zip Code', 'Latitude', 'Longitude', 'Count', 'Country', 'State', 'Churn Reason', 'Churn Value']

# Drop the columns
df.drop(columns=columns_to_drop, inplace=True, errors='ignore')

# Verify remaining columns
print("Columns after dropping irrelevant ones:")
print(df.columns)
Columns after dropping irrelevant ones:
Index(['City', 'Gender', 'Senior Citizen', 'Partner', 'Dependents',
       'Tenure Months', 'Phone Service', 'Multiple Lines', 'Internet Service',
       'Online Security', 'Online Backup', 'Device Protection', 'Tech Support',
       'Streaming TV', 'Streaming Movies', 'Contract', 'Paperless Billing',
       'Payment Method', 'Monthly Charges', 'Total Charges', 'Churn Label',
       'Churn Score', 'CLTV'],
      dtype='object')
In [622]:
binary_columns = ['Gender', 'Senior Citizen', 'Partner', 'Dependents', 'Phone Service', 'Paperless Billing', 'Churn Label']
for col in binary_columns:
    if col in df.columns:
       df[col] = df[col].map({'Yes': 1, 'No': 0})
In [623]:
to_get_dummies_for = [
    'City', 'Gender', 'Multiple Lines', 'Internet Service',
    'Online Security', 'Online Backup', 'Device Protection',
    'Tech Support', 'Streaming TV',  'Streaming Movies',
    'Contract', 'Payment Method', 'Churn Label'
]

# Create dummy variables for the listed columns
df = pd.get_dummies(data=df, columns=to_get_dummies_for, drop_first=True)

# Verify dummy variable creation
print("Dataframe after dummy variable creation:")
print(df.head())
Dataframe after dummy variable creation:
   Senior Citizen  Partner  Dependents  Tenure Months  Phone Service  \
0               0        0           0              2              1   
1               0        0           1              2              1   
2               0        0           1              8              1   
3               0        1           1             28              1   
4               0        0           1             49              1   

   Paperless Billing  Monthly Charges Total Charges  Churn Score  CLTV  ...  \
0                  1            53.85        108.15           86  3239  ...   
1                  1            70.70        151.65           67  2701  ...   
2                  1            99.65         820.5           86  5372  ...   
3                  1           104.80       3046.05           84  5003  ...   
4                  1           103.70        5036.3           89  5340  ...   

   Streaming TV_No internet service  Streaming TV_Yes  \
0                             False             False   
1                             False             False   
2                             False              True   
3                             False              True   
4                             False              True   

   Streaming Movies_No internet service  Streaming Movies_Yes  \
0                                 False                 False   
1                                 False                 False   
2                                 False                  True   
3                                 False                  True   
4                                 False                  True   

   Contract_One year  Contract_Two year  \
0              False              False   
1              False              False   
2              False              False   
3              False              False   
4              False              False   

   Payment Method_Credit card (automatic)  Payment Method_Electronic check  \
0                                   False                            False   
1                                   False                             True   
2                                   False                             True   
3                                   False                             True   
4                                   False                            False   

   Payment Method_Mailed check  Churn Label_1  
0                         True           True  
1                        False           True  
2                        False           True  
3                        False           True  
4                        False           True  

[5 rows x 1160 columns]
In [624]:
# Define target variable
target_column = 'Churn Label'

if target_column in df.columns:
    y = df[target_column]
    X = df.drop(columns=[target_column])
else:
    print(f"Error: Target column '{target_column}' not found in dataset.")
Error: Target column 'Churn Label' not found in dataset.
In [625]:
df.info()
df.head()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7043 entries, 0 to 7042
Columns: 1160 entries, Senior Citizen to Churn Label_1
dtypes: bool(1150), float64(1), int64(8), object(1)
memory usage: 8.3+ MB
Out[625]:
Senior Citizen Partner Dependents Tenure Months Phone Service Paperless Billing Monthly Charges Total Charges Churn Score CLTV ... Streaming TV_No internet service Streaming TV_Yes Streaming Movies_No internet service Streaming Movies_Yes Contract_One year Contract_Two year Payment Method_Credit card (automatic) Payment Method_Electronic check Payment Method_Mailed check Churn Label_1
0 0 0 0 2 1 1 53.85 108.15 86 3239 ... False False False False False False False False True True
1 0 0 1 2 1 1 70.70 151.65 67 2701 ... False False False False False False False True False True
2 0 0 1 8 1 1 99.65 820.5 86 5372 ... False True False True False False False True False True
3 0 1 1 28 1 1 104.80 3046.05 84 5003 ... False True False True False False False True False True
4 0 0 1 49 1 1 103.70 5036.3 89 5340 ... False True False True False False False False False True

5 rows × 1160 columns

Splitting Data Train (70%) and Test (30%)¶

In [626]:
# Assuming your data is in a pandas DataFrame
X = pd.DataFrame(X)
y = pd.Series(y)

# Identify and convert non-numeric values to NaN
X = X.apply(pd.to_numeric, errors='coerce')

# Handle NaN values: fill with 0, mean, median, or drop them
X = X.fillna(0)  # You can choose to fill with other strategies like mean, median, etc.

# Proceed with the train-test split and scaling
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

Logistics Regression¶

In [628]:
# Initialize the Logistic Regression model
log_reg = LogisticRegression(random_state=42)

# Fit the model on the training data
log_reg.fit(X_train_scaled, y_train)

# Check model coefficients
print("Model Coefficients:", log_reg.coef_)
print("Intercept:", log_reg.intercept_)
Model Coefficients: [[ 0.          0.          0.         ... -0.02735146  0.11801895
  -0.00196408]]
Intercept: [-4.31144835]
In [629]:
# Predict on the training set
y_train_pred = log_reg.predict(X_train_scaled)
y_train_prob = log_reg.predict_proba(X_train_scaled)

# Predict on the testing set
y_test_pred = log_reg.predict(X_test_scaled)
y_test_prob = log_reg.predict_proba(X_test_scaled)
In [630]:
# Instantiate the LogisticRegression model
model = LogisticRegression()

# Fit the model to the training data
model.fit(X_train_scaled, y_train)
Out[630]:
LogisticRegression()
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
LogisticRegression()
In [631]:
print("=== Training Performance ===")
print(classification_report(y_train, y_train_pred))

# Confusion Matrix for Training
cm_train = confusion_matrix(y_train, y_train_pred)
sns.heatmap(cm_train, annot=True, fmt='d', cmap='Blues', xticklabels=['Not Churn', 'Churn'], yticklabels=['Not Churn', 'Churn'])
plt.title("Confusion Matrix - Training Data")
plt.xlabel("Predicted")
plt.ylabel("Actual")
plt.show()
=== Training Performance ===
              precision    recall  f1-score   support

          No       1.00      1.00      1.00      3622
         Yes       1.00      1.00      1.00      1308

    accuracy                           1.00      4930
   macro avg       1.00      1.00      1.00      4930
weighted avg       1.00      1.00      1.00      4930

No description has been provided for this image
In [632]:
print("=== Testing Performance ===")
print(classification_report(y_test, y_test_pred))

# Confusion Matrix for Testing
cm_test = confusion_matrix(y_test, y_test_pred)
sns.heatmap(cm_test, annot=True, fmt='d', cmap='Blues', xticklabels=['Not Churn', 'Churn'], yticklabels=['Not Churn', 'Churn'])
plt.title("Confusion Matrix - Testing Data")
plt.xlabel("Predicted")
plt.ylabel("Actual")
plt.show()
=== Testing Performance ===
              precision    recall  f1-score   support

          No       1.00      1.00      1.00      1552
         Yes       1.00      1.00      1.00       561

    accuracy                           1.00      2113
   macro avg       1.00      1.00      1.00      2113
weighted avg       1.00      1.00      1.00      2113

No description has been provided for this image

Support Vector Machine (SVM)¶

In [633]:
# Create the SVM model with linear kernel
svm_model = SVC(kernel='linear')

# Train the model
svm_model.fit(X_train_scaled, y_train)
Out[633]:
SVC(kernel='linear')
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
SVC(kernel='linear')
In [634]:
# Make predictions on the training data
y_train_pred = svm_model.predict(X_train_scaled)

# Evaluate the training performance
print("=== Training Performance ===")
print(classification_report(y_train, y_train_pred))

# Confusion matrix for training data
cm_train = confusion_matrix(y_train, y_train_pred)
sns.heatmap(cm_train, annot=True, fmt='d', cmap='Blues', xticklabels=['Not Churn', 'Churn'], yticklabels=['Not Churn', 'Churn'])
plt.title('Confusion Matrix - Training Data')
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.show()
=== Training Performance ===
              precision    recall  f1-score   support

          No       1.00      1.00      1.00      3622
         Yes       1.00      1.00      1.00      1308

    accuracy                           1.00      4930
   macro avg       1.00      1.00      1.00      4930
weighted avg       1.00      1.00      1.00      4930

No description has been provided for this image
In [635]:
# Make predictions on the test data
y_test_pred = svm_model.predict(X_test_scaled)

# Evaluate the test performance
print("=== Test Performance ===")
print(classification_report(y_test, y_test_pred))

# Confusion matrix for test data
cm_test = confusion_matrix(y_test, y_test_pred)
sns.heatmap(cm_test, annot=True, fmt='d', cmap='Blues', xticklabels=['Not Churn', 'Churn'], yticklabels=['Not Churn', 'Churn'])
plt.title('Confusion Matrix - Test Data')
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.show()
=== Test Performance ===
              precision    recall  f1-score   support

          No       1.00      1.00      1.00      1552
         Yes       1.00      1.00      1.00       561

    accuracy                           1.00      2113
   macro avg       1.00      1.00      1.00      2113
weighted avg       1.00      1.00      1.00      2113

No description has been provided for this image
In [ ]: