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()
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()
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>
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()
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
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
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
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
In [ ]: