6.3.7. Telco Customer Churn (IBM)#
6.3.7.1. Summary#
Customer data of a telecommunications company from IBM’s sample data sets, published on Kaggle [1]. Each row is a customer, described by the services they subscribe to, their account and a few demographics, with a label indicating whether they left within the last month.
The 11 customers without a TotalCharges, all with a tenure of 0 months, are dropped, as
in Vanderschueren et al. [2]. Every customer’s monthly charge is known, and it drives the cost
matrix: missing a churner loses a year of their charges, while a retention offer costs two months
of them.
Classes |
2 |
Churners |
1869 |
Non-churners |
5163 |
Samples |
7032 |
Features |
19 |
6.3.7.2. Using the Dataset#
The dataset is fetched through fetch_telco_customer_churn. It is
downloaded from OpenML on first use and cached under ~/empulse_data (override with
$EMPULSE_DATA_HOME or the data_home argument), so later calls work offline.
It returns a Dataset object with the following attributes:
data: the feature matrixtarget: the target vectorcost_matrix: aCostMatrixwith default values pre-filledinstance_costs: a dict of per-instance cost drivers ('monthly_charges')feature_names: the feature namestarget_names: the target namesDESCR: the full description of the dataset
import pandas as pd
from empulse.datasets import fetch_telco_customer_churn
dataset = fetch_telco_customer_churn(backend=pd)
X, y = dataset.data, dataset.target
The backend argument selects the dataframe library used for data and target.
Pass the module itself — backend=pd for pandas or backend=pl for polars.
Most features are categorical. Pass the cost matrix to the model as a
Metric loss, and hand it the monthly charges at fit time:
from empulse.metrics import Metric, Cost
from empulse.models import CSLogitClassifier
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
numeric = X.select_dtypes(include=['number']).columns
categorical = X.select_dtypes(exclude=['number']).columns
pipeline = Pipeline([
('preprocessor', ColumnTransformer([
('num', StandardScaler(), numeric),
('cat', OneHotEncoder(handle_unknown='ignore', sparse_output=False), categorical),
])),
('model', CSLogitClassifier(loss=Metric(dataset.cost_matrix, Cost()))),
])
pipeline.fit(X, y, model__monthly_charges=dataset.instance_costs['monthly_charges'])
6.3.7.3. Cost Matrix#
A churner who is not targeted leaves, which costs \(n_{FN}\) months of their monthly charge \(A_i\). Targeting a customer who would have stayed wastes a retention offer worth \(n_{FP}\) months of charges. Following Vanderschueren et al. [2], who take the scheme from Petrides & Verbeke [3], correctly targeted churners and correctly ignored customers cost nothing.
Actual churner \(y_i = 1\) |
Actual non-churner \(y_i = 0\) |
|
Predicted churner \(\hat{y}_i = 1\) |
|
|
Predicted non-churner \(\hat{y}_i = 0\) |
|
|
The numbers of months are symbolic parameters with the defaults of the paper, and can be overridden by passing their name:
Parameter |
Default |
Meaning |
|---|---|---|
|
12 |
Months of charges lost when a churner is missed |
|
2 |
Months of charges given away as a retention offer |
y_score = pipeline.predict_proba(X)[:, 1]
cost = Metric(dataset.cost_matrix, Cost())
default_cost = cost(y, y_score, **dataset.instance_costs)
cheaper_offer = cost(y, y_score, fp_months=1, **dataset.instance_costs)
6.3.7.4. Data Description#
Feature |
Description |
Type |
|---|---|---|
|
|
categorical |
|
Whether the customer is a senior citizen (1 = yes, 0 = no) |
binary |
|
Whether the customer has a partner |
categorical |
|
Whether the customer has dependents |
categorical |
|
Number of months the customer has stayed with the company |
numeric |
|
Whether the customer has a phone service |
categorical |
|
Whether the customer has multiple lines (or no phone service) |
categorical |
|
Internet service provider: |
categorical |
|
Whether the customer has each add-on (or no internet service) |
categorical |
|
Whether the customer streams TV or movies (or has no internet service) |
categorical |
|
Contract term: |
categorical |
|
Whether the customer has paperless billing |
categorical |
|
Electronic check, mailed check, bank transfer or credit card |
categorical |
|
Amount charged to the customer each month; also the cost driver |
numeric |
|
Total amount charged to the customer |
numeric |
churn (target) |
Whether the customer left within the last month (1 = yes, 0 = no) |
binary |