Пример использование подходов из sklift.models в sklearn.pipeline



SCIKIT-UPLIFT REPO | SCIKIT-UPLIFT DOCS | USER GUIDE
ENGLISH VERSION

В данном ноутбуке рассмотрим простой пример применения одного из подходов прогнозирования uplift в sklearn.pipeline.

Данные для примера взяты из MineThatData E-Mail Analytics And Data Mining Challenge dataset by Kevin Hillstrom. Этот набор данных содержит 64 000 клиентов, которые в последний раз совершали покупки в течение двенадцати месяцев. Среди клиентов была проведена рекламная кампания с помощью email рассылки:

  • 1/3 клиентов были выбраны случайным образом для получения электронного письма, рекламирующего мужскую продукцию;
  • 1/3 клиентов были выбраны случайным образом для получения электронного письма, рекламирующего женскую продукцию;
  • С оставшейся 1/3 коммуникацию не проводили.

Для каждого клиента из выборки замерили факт перехода по ссылке в письме, факт совершения покупки и сумму трат за две недели, следущими после получения письма.

Полное описание датасета можной найти по ссылке.

Установим необходимые библиотеки:

In [1]:
!pip install scikit-uplift xgboost==1.0.2 category_encoders==2.1.0 -U

Загрузим данные:

In [2]:
import urllib.request


csv_path = '/content/Hilstorm.csv'
url = 'http://www.minethatdata.com/Kevin_Hillstrom_MineThatData_E-MailAnalytics_DataMiningChallenge_2008.03.20.csv'
urllib.request.urlretrieve(url, csv_path)

Для простоты примера оставим только два сегмента пользователей:

  • тем, кому рассылалась по электронной почте рекламная кампания с участием женских товаров;
  • тем, кому не рассылалась рекламная кампания.

В качестве целевой переменной будем использовать переменную visit.

In [3]:
import pandas as pd


%matplotlib inline

dataset = pd.read_csv(csv_path)
print(f'Размер датасета до обработки: {dataset.shape}')
dataset = dataset[dataset['segment']!='Mens E-Mail']
dataset.loc[:, 'treatment'] = dataset['segment'].map({
    'Womens E-Mail': 1,
    'No E-Mail': 0
})

dataset = dataset.drop(['segment', 'conversion', 'spend'], axis=1)
print(f'Размер датасета после обработки: {dataset.shape}')
dataset.head()
Размер датасета до обработки: (64000, 12)
Размер датасета после обработки: (42693, 10)
Out[3]:
recency history_segment history mens womens zip_code newbie channel visit treatment
0 10 2) $100 - $200 142.44 1 0 Surburban 0 Phone 0 1
1 6 3) $200 - $350 329.08 1 1 Rural 1 Web 0 0
2 7 2) $100 - $200 180.65 0 1 Surburban 1 Web 0 1
4 2 1) $0 - $100 45.34 1 0 Urban 0 Web 0 1
5 6 2) $100 - $200 134.83 0 1 Surburban 0 Phone 1 1

Разобъем все данные на обучающую и валидационную выборку:

In [4]:
from sklearn.model_selection import train_test_split


Xyt_tr, Xyt_val = train_test_split(dataset, test_size=0.5, random_state=42)

X_tr = Xyt_tr.drop(['visit', 'treatment'], axis=1)
y_tr = Xyt_tr['visit']
treat_tr = Xyt_tr['treatment']

X_val = Xyt_val.drop(['visit', 'treatment'], axis=1)
y_val = Xyt_val['visit']
treat_val = Xyt_val['treatment']

Select categorical features:

In [5]:
cat_cols = X_tr.select_dtypes(include='object').columns.tolist()
print(cat_cols)
['history_segment', 'zip_code', 'channel']

Создадим нужные объекты и объединим их в pipieline.

In [6]:
from sklearn.pipeline import Pipeline
from category_encoders import CatBoostEncoder
from sklift.models import ClassTransformation
from xgboost import XGBClassifier


encoder = CatBoostEncoder(cols=cat_cols)
estimator = XGBClassifier(max_depth=2, random_state=42)
ct = ClassTransformation(estimator=estimator)

my_pipeline = Pipeline([
    ('encoder', encoder),
    ('model', ct)
])

Обучать pipeline будем как обычно, но колонку treatment добавим как параметр шага model: `model__treatment`.

In [7]:
my_pipeline = my_pipeline.fit(
    X=X_tr,
    y=y_tr,
    model__treatment=treat_tr
)
/Users/Maksim/Library/Python/3.6/lib/python/site-packages/sklearn/pipeline.py:354: UserWarning: It is recommended to use this approach on treatment balanced data. Current sample size is unbalanced.
  self._final_estimator.fit(Xt, y, **fit_params)

Предскажем uplift и посчитаем [email protected]%

In [8]:
from sklift.metrics import uplift_at_k


uplift_predictions = my_pipeline.predict(X_val)

uplift_30 = uplift_at_k(y_val, uplift_predictions, treat_val, strategy='overall')
print(f'[email protected]%: {uplift_30:.4f}')