Dataset Guide — Customer Churn Analysis¶
Source¶
Dataset: IBM/Kaggle Telco Customer Churn
URL: https://www.kaggle.com/datasets/blastchar/telco-customer-churn
File: WA_Fn-UseC_-Telco-Customer-Churn.csv
Size: 7,043 rows × 21 columns
Column Descriptions¶
| Column | Type | Description | Notes |
|---|---|---|---|
customerID |
str | Unique customer identifier | Format: XXXX-XXXXX |
gender |
str | Customer gender | "Male" or "Female" |
SeniorCitizen |
int | Is customer a senior citizen? | 0 or 1 |
Partner |
str | Has a partner? | "Yes" or "No" |
Dependents |
str | Has dependents? | "Yes" or "No" |
tenure |
int | Months as a customer | 0 to 72 |
PhoneService |
str | Has phone service? | "Yes" or "No" |
MultipleLines |
str | Multiple phone lines? | "Yes", "No", "No phone service" |
InternetService |
str | Internet service provider | "DSL", "Fiber optic", "No" |
OnlineSecurity |
str | Online security add-on | "Yes", "No", "No internet service" |
OnlineBackup |
str | Online backup add-on | "Yes", "No", "No internet service" |
DeviceProtection |
str | Device protection add-on | "Yes", "No", "No internet service" |
TechSupport |
str | Tech support add-on | "Yes", "No", "No internet service" |
StreamingTV |
str | Streaming TV subscription | "Yes", "No", "No internet service" |
StreamingMovies |
str | Streaming movies subscription | "Yes", "No", "No internet service" |
Contract |
str | Contract type | "Month-to-month", "One year", "Two year" |
PaperlessBilling |
str | Paperless billing enrolled? | "Yes" or "No" |
PaymentMethod |
str | Payment method | "Electronic check", "Mailed check", "Bank transfer (automatic)", "Credit card (automatic)" |
MonthlyCharges |
float | Monthly charge amount (£) | Range: 18.25 – 118.75 |
TotalCharges |
str | Total charges to date | Note: stored as string, has blanks for new customers |
Churn |
str | Did customer churn? | "Yes" or "No" — this is our target variable |
Key Data Quality Issues¶
| Issue | Column | Fix |
|---|---|---|
TotalCharges is a string, not float |
TotalCharges |
pd.to_numeric(..., errors="coerce") |
11 rows have blank TotalCharges |
TotalCharges |
These are new customers with tenure=0 — fill with 0 or drop |
SeniorCitizen is 0/1 not Yes/No |
SeniorCitizen |
Convert to "Yes"/"No" for consistency |
| Three-way "No internet service" values | Multiple add-on columns | Simplify to "Yes"/"No" or group with "No" |
Summary Statistics¶
import pandas as pd
df = pd.read_csv("WA_Fn-UseC_-Telco-Customer-Churn.csv")
print(df.shape) # (7043, 21)
print(df["Churn"].value_counts(normalize=True))
# No 0.7347
# Yes 0.2653
print(df["tenure"].describe())
# mean=32.4, median=29.0, std=24.6, min=0, max=72
Churn rate in this dataset: 26.5% — higher than a typical telecom company. This is intentional — the dataset is designed to make churn visible.
Tenure Buckets¶
Create this segmentation for analysis:
| Bucket | Months | Label |
|---|---|---|
| New | 0–6 | "New (< 6 months)" |
| Growing | 7–24 | "Growing (6–24 months)" |
| Established | 25–48 | "Established (2–4 years)" |
| Loyal | 49+ | "Loyal (4+ years)" |
Quick Data Exploration¶
import pandas as pd
df = pd.read_csv("WA_Fn-UseC_-Telco-Customer-Churn.csv")
df["TotalCharges"] = pd.to_numeric(df["TotalCharges"], errors="coerce")
# Churn rate by contract type
print(df.groupby("Contract")["Churn"].apply(lambda x: (x == "Yes").mean()).round(3))
# Month-to-month 0.427
# One year 0.113
# Two year 0.029
# Average tenure by churn status
print(df.groupby("Churn")["tenure"].mean().round(1))
# Churn
# No 37.6
# Yes 18.0