BDC-team-1/Sport/Modelization/CA_segment_sport.ipynb

4195 lines
233 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"id": "84b6e27e-4bda-4d38-8689-ec7fc0da1848",
"metadata": {},
"source": [
"# Define segment and predict sales associated"
]
},
{
"cell_type": "markdown",
"id": "ec059482-45d3-4ae6-99bc-9b4ced115db3",
"metadata": {},
"source": [
"## Importations of packages "
]
},
{
"cell_type": "code",
"execution_count": 48,
"id": "9771bf29-d08e-4674-8c23-9a2672fbef8f",
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"from pandas import DataFrame\n",
"import numpy as np\n",
"import os\n",
"import s3fs\n",
"import re\n",
"from sklearn.linear_model import LogisticRegression\n",
"from sklearn.ensemble import RandomForestClassifier\n",
"from sklearn.metrics import accuracy_score, confusion_matrix, classification_report, recall_score\n",
"from sklearn.utils import class_weight\n",
"from sklearn.neighbors import KNeighborsClassifier\n",
"from sklearn.pipeline import Pipeline\n",
"from sklearn.compose import ColumnTransformer\n",
"from sklearn.preprocessing import OneHotEncoder\n",
"from sklearn.impute import SimpleImputer\n",
"from sklearn.model_selection import GridSearchCV\n",
"from sklearn.preprocessing import StandardScaler, MaxAbsScaler, MinMaxScaler\n",
"from sklearn.metrics import make_scorer, f1_score, balanced_accuracy_score\n",
"import seaborn as sns\n",
"import matplotlib.pyplot as plt\n",
"from sklearn.metrics import roc_curve, auc, precision_recall_curve, average_precision_score\n",
"from sklearn.exceptions import ConvergenceWarning, DataConversionWarning\n",
"from sklearn.naive_bayes import GaussianNB\n",
"from scipy.optimize import fsolve\n",
"\n",
"import pickle\n",
"import warnings"
]
},
{
"cell_type": "markdown",
"id": "048fcd7c-800a-4a6b-b725-faf8410f924a",
"metadata": {},
"source": [
"## load databases"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "539ccbdf-f29f-4f04-99c1-8c88d0efe514",
"metadata": {},
"outputs": [],
"source": [
"# Create filesystem object\n",
"S3_ENDPOINT_URL = \"https://\" + os.environ[\"AWS_S3_ENDPOINT\"]\n",
"fs = s3fs.S3FileSystem(client_kwargs={'endpoint_url': S3_ENDPOINT_URL})"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "0c3a6ddc-9345-4a42-b6bf-a20a95de3028",
"metadata": {},
"outputs": [],
"source": [
"def load_train_test():\n",
" BUCKET = \"projet-bdc2324-team1/Generalization/sport\"\n",
" File_path_train = BUCKET + \"/Train_set.csv\"\n",
" File_path_test = BUCKET + \"/Test_set.csv\"\n",
" \n",
" with fs.open( File_path_train, mode=\"rb\") as file_in:\n",
" dataset_train = pd.read_csv(file_in, sep=\",\")\n",
" # dataset_train['y_has_purchased'] = dataset_train['y_has_purchased'].fillna(0)\n",
"\n",
" with fs.open(File_path_test, mode=\"rb\") as file_in:\n",
" dataset_test = pd.read_csv(file_in, sep=\",\")\n",
" # dataset_test['y_has_purchased'] = dataset_test['y_has_purchased'].fillna(0)\n",
" \n",
" return dataset_train, dataset_test"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "2831d546-b365-498b-8248-c618bd9c3057",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_519/2459610029.py:7: DtypeWarning: Columns (38) have mixed types. Specify dtype option on import or set low_memory=False.\n",
" dataset_train = pd.read_csv(file_in, sep=\",\")\n"
]
},
{
"data": {
"text/plain": [
"customer_id 0\n",
"nb_tickets 0\n",
"nb_purchases 0\n",
"total_amount 0\n",
"nb_suppliers 0\n",
"vente_internet_max 0\n",
"purchase_date_min 0\n",
"purchase_date_max 0\n",
"time_between_purchase 0\n",
"nb_tickets_internet 0\n",
"street_id 0\n",
"structure_id 222825\n",
"mcp_contact_id 70874\n",
"fidelity 0\n",
"tenant_id 0\n",
"is_partner 0\n",
"deleted_at 224213\n",
"gender 0\n",
"is_email_true 0\n",
"opt_in 0\n",
"last_buying_date 66139\n",
"max_price 66139\n",
"ticket_sum 0\n",
"average_price 66023\n",
"average_purchase_delay 66139\n",
"average_price_basket 66139\n",
"average_ticket_basket 66139\n",
"total_price 116\n",
"purchase_count 0\n",
"first_buying_date 66139\n",
"country 23159\n",
"gender_label 0\n",
"gender_female 0\n",
"gender_male 0\n",
"gender_other 0\n",
"country_fr 23159\n",
"nb_campaigns 0\n",
"nb_campaigns_opened 0\n",
"time_to_open 123159\n",
"y_has_purchased 0\n",
"dtype: int64"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dataset_train, dataset_test = load_train_test()\n",
"dataset_train.isna().sum()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "b8827f7b-b304-4f51-9814-c7a98ed88cf0",
"metadata": {},
"outputs": [],
"source": [
"def features_target_split(dataset_train, dataset_test):\n",
" \n",
" features_l = ['nb_tickets', 'nb_purchases', 'total_amount', 'nb_suppliers', 'vente_internet_max', 'purchase_date_min', 'purchase_date_max', \n",
" 'time_between_purchase', 'nb_tickets_internet', 'fidelity', 'is_email_true', 'opt_in', #'is_partner',\n",
" 'gender_female', 'gender_male', 'gender_other', 'nb_campaigns', 'nb_campaigns_opened']\n",
"\n",
" # we suppress fidelity, time between purchase, and gender other (colinearity issue)\n",
" \"\"\"\n",
" features_l = ['nb_tickets', 'nb_purchases', 'total_amount', 'nb_suppliers', 'vente_internet_max', \n",
" 'purchase_date_min', 'purchase_date_max', 'nb_tickets_internet', 'is_email_true', \n",
" 'opt_in', 'gender_female', 'gender_male', 'nb_campaigns', 'nb_campaigns_opened']\n",
" \"\"\"\n",
" \n",
" X_train = dataset_train[features_l]\n",
" y_train = dataset_train[['y_has_purchased']]\n",
"\n",
" X_test = dataset_test[features_l]\n",
" y_test = dataset_test[['y_has_purchased']]\n",
" return X_train, X_test, y_train, y_test"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "c18195fc-ed40-4e39-a59e-c9ecc5a8e6c3",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Shape train : (224213, 17)\n",
"Shape test : (96096, 17)\n"
]
}
],
"source": [
"X_train, X_test, y_train, y_test = features_target_split(dataset_train, dataset_test)\n",
"print(\"Shape train : \", X_train.shape)\n",
"print(\"Shape test : \", X_test.shape)"
]
},
{
"cell_type": "markdown",
"id": "74eda066-5e01-43aa-b0cf-cc6d9bbf770e",
"metadata": {},
"source": [
"## get results from the logit cross validated model"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "7c81390e-598c-4f02-bd56-dd03b00dcb33",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>nb_tickets</th>\n",
" <th>nb_purchases</th>\n",
" <th>total_amount</th>\n",
" <th>nb_suppliers</th>\n",
" <th>vente_internet_max</th>\n",
" <th>purchase_date_min</th>\n",
" <th>purchase_date_max</th>\n",
" <th>time_between_purchase</th>\n",
" <th>nb_tickets_internet</th>\n",
" <th>fidelity</th>\n",
" <th>is_email_true</th>\n",
" <th>opt_in</th>\n",
" <th>gender_female</th>\n",
" <th>gender_male</th>\n",
" <th>gender_other</th>\n",
" <th>nb_campaigns</th>\n",
" <th>nb_campaigns_opened</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>4.0</td>\n",
" <td>1.0</td>\n",
" <td>100.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>5.177187</td>\n",
" <td>5.177187</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>55.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>426.265613</td>\n",
" <td>426.265613</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>2</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>17.0</td>\n",
" <td>1.0</td>\n",
" <td>80.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>436.033437</td>\n",
" <td>436.033437</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>2</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>4.0</td>\n",
" <td>1.0</td>\n",
" <td>120.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>5.196412</td>\n",
" <td>5.196412</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>34.0</td>\n",
" <td>2.0</td>\n",
" <td>416.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>478.693148</td>\n",
" <td>115.631470</td>\n",
" <td>363.061678</td>\n",
" <td>0.0</td>\n",
" <td>4</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96091</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>67.31</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>278.442257</td>\n",
" <td>278.442257</td>\n",
" <td>0.000000</td>\n",
" <td>1.0</td>\n",
" <td>2</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>15.0</td>\n",
" <td>5.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96092</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>61.41</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>189.207373</td>\n",
" <td>189.207373</td>\n",
" <td>0.000000</td>\n",
" <td>1.0</td>\n",
" <td>1</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>12.0</td>\n",
" <td>9.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96093</th>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>550.000000</td>\n",
" <td>550.000000</td>\n",
" <td>-1.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>29.0</td>\n",
" <td>3.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96094</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>79.43</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>279.312905</td>\n",
" <td>279.312905</td>\n",
" <td>0.000000</td>\n",
" <td>1.0</td>\n",
" <td>1</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>20.0</td>\n",
" <td>4.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96095</th>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>550.000000</td>\n",
" <td>550.000000</td>\n",
" <td>-1.000000</td>\n",
" <td>0.0</td>\n",
" <td>2</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>31.0</td>\n",
" <td>4.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>96096 rows × 17 columns</p>\n",
"</div>"
],
"text/plain": [
" nb_tickets nb_purchases total_amount nb_suppliers \\\n",
"0 4.0 1.0 100.00 1.0 \n",
"1 1.0 1.0 55.00 1.0 \n",
"2 17.0 1.0 80.00 1.0 \n",
"3 4.0 1.0 120.00 1.0 \n",
"4 34.0 2.0 416.00 1.0 \n",
"... ... ... ... ... \n",
"96091 1.0 1.0 67.31 1.0 \n",
"96092 1.0 1.0 61.41 1.0 \n",
"96093 0.0 0.0 0.00 0.0 \n",
"96094 1.0 1.0 79.43 1.0 \n",
"96095 0.0 0.0 0.00 0.0 \n",
"\n",
" vente_internet_max purchase_date_min purchase_date_max \\\n",
"0 0.0 5.177187 5.177187 \n",
"1 0.0 426.265613 426.265613 \n",
"2 0.0 436.033437 436.033437 \n",
"3 0.0 5.196412 5.196412 \n",
"4 0.0 478.693148 115.631470 \n",
"... ... ... ... \n",
"96091 1.0 278.442257 278.442257 \n",
"96092 1.0 189.207373 189.207373 \n",
"96093 0.0 550.000000 550.000000 \n",
"96094 1.0 279.312905 279.312905 \n",
"96095 0.0 550.000000 550.000000 \n",
"\n",
" time_between_purchase nb_tickets_internet fidelity is_email_true \\\n",
"0 0.000000 0.0 1 True \n",
"1 0.000000 0.0 2 True \n",
"2 0.000000 0.0 2 True \n",
"3 0.000000 0.0 1 True \n",
"4 363.061678 0.0 4 True \n",
"... ... ... ... ... \n",
"96091 0.000000 1.0 2 True \n",
"96092 0.000000 1.0 1 True \n",
"96093 -1.000000 0.0 1 True \n",
"96094 0.000000 1.0 1 True \n",
"96095 -1.000000 0.0 2 True \n",
"\n",
" opt_in gender_female gender_male gender_other nb_campaigns \\\n",
"0 False 1 0 0 0.0 \n",
"1 True 0 1 0 0.0 \n",
"2 True 1 0 0 0.0 \n",
"3 False 1 0 0 0.0 \n",
"4 False 1 0 0 0.0 \n",
"... ... ... ... ... ... \n",
"96091 False 0 1 0 15.0 \n",
"96092 False 0 1 0 12.0 \n",
"96093 True 1 0 0 29.0 \n",
"96094 False 0 1 0 20.0 \n",
"96095 False 0 1 0 31.0 \n",
"\n",
" nb_campaigns_opened \n",
"0 0.0 \n",
"1 0.0 \n",
"2 0.0 \n",
"3 0.0 \n",
"4 0.0 \n",
"... ... \n",
"96091 5.0 \n",
"96092 9.0 \n",
"96093 3.0 \n",
"96094 4.0 \n",
"96095 4.0 \n",
"\n",
"[96096 rows x 17 columns]"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X_test"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "c708f439-bb75-4688-bf4f-4c04e13deaae",
"metadata": {},
"outputs": [],
"source": [
"def load_model(type_of_activity, model):\n",
" BUCKET = f\"projet-bdc2324-team1/Output_model/{type_of_activity}/{model}/\"\n",
" filename = model + '.pkl'\n",
" file_path = BUCKET + filename\n",
" with fs.open(file_path, mode=\"rb\") as f:\n",
" model_bytes = f.read()\n",
"\n",
" model = pickle.loads(model_bytes)\n",
" return model"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "5261a803-05b8-41a0-968c-dc7bde48ddd3",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>#sk-container-id-1 {\n",
" /* Definition of color scheme common for light and dark mode */\n",
" --sklearn-color-text: black;\n",
" --sklearn-color-line: gray;\n",
" /* Definition of color scheme for unfitted estimators */\n",
" --sklearn-color-unfitted-level-0: #fff5e6;\n",
" --sklearn-color-unfitted-level-1: #f6e4d2;\n",
" --sklearn-color-unfitted-level-2: #ffe0b3;\n",
" --sklearn-color-unfitted-level-3: chocolate;\n",
" /* Definition of color scheme for fitted estimators */\n",
" --sklearn-color-fitted-level-0: #f0f8ff;\n",
" --sklearn-color-fitted-level-1: #d4ebff;\n",
" --sklearn-color-fitted-level-2: #b3dbfd;\n",
" --sklearn-color-fitted-level-3: cornflowerblue;\n",
"\n",
" /* Specific color for light theme */\n",
" --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
" --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
" --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
" --sklearn-color-icon: #696969;\n",
"\n",
" @media (prefers-color-scheme: dark) {\n",
" /* Redefinition of color scheme for dark theme */\n",
" --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
" --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
" --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
" --sklearn-color-icon: #878787;\n",
" }\n",
"}\n",
"\n",
"#sk-container-id-1 {\n",
" color: var(--sklearn-color-text);\n",
"}\n",
"\n",
"#sk-container-id-1 pre {\n",
" padding: 0;\n",
"}\n",
"\n",
"#sk-container-id-1 input.sk-hidden--visually {\n",
" border: 0;\n",
" clip: rect(1px 1px 1px 1px);\n",
" clip: rect(1px, 1px, 1px, 1px);\n",
" height: 1px;\n",
" margin: -1px;\n",
" overflow: hidden;\n",
" padding: 0;\n",
" position: absolute;\n",
" width: 1px;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-dashed-wrapped {\n",
" border: 1px dashed var(--sklearn-color-line);\n",
" margin: 0 0.4em 0.5em 0.4em;\n",
" box-sizing: border-box;\n",
" padding-bottom: 0.4em;\n",
" background-color: var(--sklearn-color-background);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-container {\n",
" /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
" but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
" so we also need the `!important` here to be able to override the\n",
" default hidden behavior on the sphinx rendered scikit-learn.org.\n",
" See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
" display: inline-block !important;\n",
" position: relative;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-text-repr-fallback {\n",
" display: none;\n",
"}\n",
"\n",
"div.sk-parallel-item,\n",
"div.sk-serial,\n",
"div.sk-item {\n",
" /* draw centered vertical line to link estimators */\n",
" background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
" background-size: 2px 100%;\n",
" background-repeat: no-repeat;\n",
" background-position: center center;\n",
"}\n",
"\n",
"/* Parallel-specific style estimator block */\n",
"\n",
"#sk-container-id-1 div.sk-parallel-item::after {\n",
" content: \"\";\n",
" width: 100%;\n",
" border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
" flex-grow: 1;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-parallel {\n",
" display: flex;\n",
" align-items: stretch;\n",
" justify-content: center;\n",
" background-color: var(--sklearn-color-background);\n",
" position: relative;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-parallel-item {\n",
" display: flex;\n",
" flex-direction: column;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-parallel-item:first-child::after {\n",
" align-self: flex-end;\n",
" width: 50%;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-parallel-item:last-child::after {\n",
" align-self: flex-start;\n",
" width: 50%;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-parallel-item:only-child::after {\n",
" width: 0;\n",
"}\n",
"\n",
"/* Serial-specific style estimator block */\n",
"\n",
"#sk-container-id-1 div.sk-serial {\n",
" display: flex;\n",
" flex-direction: column;\n",
" align-items: center;\n",
" background-color: var(--sklearn-color-background);\n",
" padding-right: 1em;\n",
" padding-left: 1em;\n",
"}\n",
"\n",
"\n",
"/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
"clickable and can be expanded/collapsed.\n",
"- Pipeline and ColumnTransformer use this feature and define the default style\n",
"- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
"*/\n",
"\n",
"/* Pipeline and ColumnTransformer style (default) */\n",
"\n",
"#sk-container-id-1 div.sk-toggleable {\n",
" /* Default theme specific background. It is overwritten whether we have a\n",
" specific estimator or a Pipeline/ColumnTransformer */\n",
" background-color: var(--sklearn-color-background);\n",
"}\n",
"\n",
"/* Toggleable label */\n",
"#sk-container-id-1 label.sk-toggleable__label {\n",
" cursor: pointer;\n",
" display: block;\n",
" width: 100%;\n",
" margin-bottom: 0;\n",
" padding: 0.5em;\n",
" box-sizing: border-box;\n",
" text-align: center;\n",
"}\n",
"\n",
"#sk-container-id-1 label.sk-toggleable__label-arrow:before {\n",
" /* Arrow on the left of the label */\n",
" content: \"▸\";\n",
" float: left;\n",
" margin-right: 0.25em;\n",
" color: var(--sklearn-color-icon);\n",
"}\n",
"\n",
"#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {\n",
" color: var(--sklearn-color-text);\n",
"}\n",
"\n",
"/* Toggleable content - dropdown */\n",
"\n",
"#sk-container-id-1 div.sk-toggleable__content {\n",
" max-height: 0;\n",
" max-width: 0;\n",
" overflow: hidden;\n",
" text-align: left;\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-toggleable__content.fitted {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-toggleable__content pre {\n",
" margin: 0.2em;\n",
" border-radius: 0.25em;\n",
" color: var(--sklearn-color-text);\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-toggleable__content.fitted pre {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-fitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
" /* Expand drop-down */\n",
" max-height: 200px;\n",
" max-width: 100%;\n",
" overflow: auto;\n",
"}\n",
"\n",
"#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
" content: \"▾\";\n",
"}\n",
"\n",
"/* Pipeline/ColumnTransformer-specific style */\n",
"\n",
"#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
" color: var(--sklearn-color-text);\n",
" background-color: var(--sklearn-color-unfitted-level-2);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
" background-color: var(--sklearn-color-fitted-level-2);\n",
"}\n",
"\n",
"/* Estimator-specific style */\n",
"\n",
"/* Colorize estimator box */\n",
"#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-2);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-2);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-label label.sk-toggleable__label,\n",
"#sk-container-id-1 div.sk-label label {\n",
" /* The background is the default theme color */\n",
" color: var(--sklearn-color-text-on-default-background);\n",
"}\n",
"\n",
"/* On hover, darken the color of the background */\n",
"#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {\n",
" color: var(--sklearn-color-text);\n",
" background-color: var(--sklearn-color-unfitted-level-2);\n",
"}\n",
"\n",
"/* Label box, darken color on hover, fitted */\n",
"#sk-container-id-1 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
" color: var(--sklearn-color-text);\n",
" background-color: var(--sklearn-color-fitted-level-2);\n",
"}\n",
"\n",
"/* Estimator label */\n",
"\n",
"#sk-container-id-1 div.sk-label label {\n",
" font-family: monospace;\n",
" font-weight: bold;\n",
" display: inline-block;\n",
" line-height: 1.2em;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-label-container {\n",
" text-align: center;\n",
"}\n",
"\n",
"/* Estimator-specific */\n",
"#sk-container-id-1 div.sk-estimator {\n",
" font-family: monospace;\n",
" border: 1px dotted var(--sklearn-color-border-box);\n",
" border-radius: 0.25em;\n",
" box-sizing: border-box;\n",
" margin-bottom: 0.5em;\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-estimator.fitted {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-0);\n",
"}\n",
"\n",
"/* on hover */\n",
"#sk-container-id-1 div.sk-estimator:hover {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-2);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-estimator.fitted:hover {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-2);\n",
"}\n",
"\n",
"/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
"\n",
"/* Common style for \"i\" and \"?\" */\n",
"\n",
".sk-estimator-doc-link,\n",
"a:link.sk-estimator-doc-link,\n",
"a:visited.sk-estimator-doc-link {\n",
" float: right;\n",
" font-size: smaller;\n",
" line-height: 1em;\n",
" font-family: monospace;\n",
" background-color: var(--sklearn-color-background);\n",
" border-radius: 1em;\n",
" height: 1em;\n",
" width: 1em;\n",
" text-decoration: none !important;\n",
" margin-left: 1ex;\n",
" /* unfitted */\n",
" border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
" color: var(--sklearn-color-unfitted-level-1);\n",
"}\n",
"\n",
".sk-estimator-doc-link.fitted,\n",
"a:link.sk-estimator-doc-link.fitted,\n",
"a:visited.sk-estimator-doc-link.fitted {\n",
" /* fitted */\n",
" border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
" color: var(--sklearn-color-fitted-level-1);\n",
"}\n",
"\n",
"/* On hover */\n",
"div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
".sk-estimator-doc-link:hover,\n",
"div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
".sk-estimator-doc-link:hover {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-3);\n",
" color: var(--sklearn-color-background);\n",
" text-decoration: none;\n",
"}\n",
"\n",
"div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
".sk-estimator-doc-link.fitted:hover,\n",
"div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
".sk-estimator-doc-link.fitted:hover {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-3);\n",
" color: var(--sklearn-color-background);\n",
" text-decoration: none;\n",
"}\n",
"\n",
"/* Span, style for the box shown on hovering the info icon */\n",
".sk-estimator-doc-link span {\n",
" display: none;\n",
" z-index: 9999;\n",
" position: relative;\n",
" font-weight: normal;\n",
" right: .2ex;\n",
" padding: .5ex;\n",
" margin: .5ex;\n",
" width: min-content;\n",
" min-width: 20ex;\n",
" max-width: 50ex;\n",
" color: var(--sklearn-color-text);\n",
" box-shadow: 2pt 2pt 4pt #999;\n",
" /* unfitted */\n",
" background: var(--sklearn-color-unfitted-level-0);\n",
" border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
"}\n",
"\n",
".sk-estimator-doc-link.fitted span {\n",
" /* fitted */\n",
" background: var(--sklearn-color-fitted-level-0);\n",
" border: var(--sklearn-color-fitted-level-3);\n",
"}\n",
"\n",
".sk-estimator-doc-link:hover span {\n",
" display: block;\n",
"}\n",
"\n",
"/* \"?\"-specific style due to the `<a>` HTML tag */\n",
"\n",
"#sk-container-id-1 a.estimator_doc_link {\n",
" float: right;\n",
" font-size: 1rem;\n",
" line-height: 1em;\n",
" font-family: monospace;\n",
" background-color: var(--sklearn-color-background);\n",
" border-radius: 1rem;\n",
" height: 1rem;\n",
" width: 1rem;\n",
" text-decoration: none;\n",
" /* unfitted */\n",
" color: var(--sklearn-color-unfitted-level-1);\n",
" border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
"}\n",
"\n",
"#sk-container-id-1 a.estimator_doc_link.fitted {\n",
" /* fitted */\n",
" border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
" color: var(--sklearn-color-fitted-level-1);\n",
"}\n",
"\n",
"/* On hover */\n",
"#sk-container-id-1 a.estimator_doc_link:hover {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-3);\n",
" color: var(--sklearn-color-background);\n",
" text-decoration: none;\n",
"}\n",
"\n",
"#sk-container-id-1 a.estimator_doc_link.fitted:hover {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-3);\n",
"}\n",
"</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>GridSearchCV(cv=3, error_score=&#x27;raise&#x27;,\n",
" estimator=Pipeline(steps=[(&#x27;preprocessor&#x27;,\n",
" ColumnTransformer(transformers=[(&#x27;num&#x27;,\n",
" Pipeline(steps=[(&#x27;scaler&#x27;,\n",
" StandardScaler())]),\n",
" [&#x27;nb_tickets&#x27;,\n",
" &#x27;nb_purchases&#x27;,\n",
" &#x27;total_amount&#x27;,\n",
" &#x27;nb_suppliers&#x27;,\n",
" &#x27;vente_internet_max&#x27;,\n",
" &#x27;purchase_date_min&#x27;,\n",
" &#x27;purchase_date_max&#x27;,\n",
" &#x27;time_between_purchase&#x27;,\n",
" &#x27;nb_tickets_internet&#x27;,\n",
" &#x27;nb_campaigns&#x27;,\n",
" &#x27;nb_...\n",
" 1.562500e-02, 3.125000e-02, 6.250000e-02, 1.250000e-01,\n",
" 2.500000e-01, 5.000000e-01, 1.000000e+00, 2.000000e+00,\n",
" 4.000000e+00, 8.000000e+00, 1.600000e+01, 3.200000e+01,\n",
" 6.400000e+01]),\n",
" &#x27;LogisticRegression_cv__class_weight&#x27;: [&#x27;balanced&#x27;,\n",
" {0.0: 0.5837086520288036,\n",
" 1.0: 3.486549107420539}],\n",
" &#x27;LogisticRegression_cv__penalty&#x27;: [&#x27;l1&#x27;, &#x27;l2&#x27;]},\n",
" scoring=make_scorer(recall_score, response_method=&#x27;predict&#x27;))</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" ><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;&nbsp;GridSearchCV<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.model_selection.GridSearchCV.html\">?<span>Documentation for GridSearchCV</span></a><span class=\"sk-estimator-doc-link fitted\">i<span>Fitted</span></span></label><div class=\"sk-toggleable__content fitted\"><pre>GridSearchCV(cv=3, error_score=&#x27;raise&#x27;,\n",
" estimator=Pipeline(steps=[(&#x27;preprocessor&#x27;,\n",
" ColumnTransformer(transformers=[(&#x27;num&#x27;,\n",
" Pipeline(steps=[(&#x27;scaler&#x27;,\n",
" StandardScaler())]),\n",
" [&#x27;nb_tickets&#x27;,\n",
" &#x27;nb_purchases&#x27;,\n",
" &#x27;total_amount&#x27;,\n",
" &#x27;nb_suppliers&#x27;,\n",
" &#x27;vente_internet_max&#x27;,\n",
" &#x27;purchase_date_min&#x27;,\n",
" &#x27;purchase_date_max&#x27;,\n",
" &#x27;time_between_purchase&#x27;,\n",
" &#x27;nb_tickets_internet&#x27;,\n",
" &#x27;nb_campaigns&#x27;,\n",
" &#x27;nb_...\n",
" 1.562500e-02, 3.125000e-02, 6.250000e-02, 1.250000e-01,\n",
" 2.500000e-01, 5.000000e-01, 1.000000e+00, 2.000000e+00,\n",
" 4.000000e+00, 8.000000e+00, 1.600000e+01, 3.200000e+01,\n",
" 6.400000e+01]),\n",
" &#x27;LogisticRegression_cv__class_weight&#x27;: [&#x27;balanced&#x27;,\n",
" {0.0: 0.5837086520288036,\n",
" 1.0: 3.486549107420539}],\n",
" &#x27;LogisticRegression_cv__penalty&#x27;: [&#x27;l1&#x27;, &#x27;l2&#x27;]},\n",
" scoring=make_scorer(recall_score, response_method=&#x27;predict&#x27;))</pre></div> </div></div><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-2\" type=\"checkbox\" ><label for=\"sk-estimator-id-2\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">estimator: Pipeline</label><div class=\"sk-toggleable__content fitted\"><pre>Pipeline(steps=[(&#x27;preprocessor&#x27;,\n",
" ColumnTransformer(transformers=[(&#x27;num&#x27;,\n",
" Pipeline(steps=[(&#x27;scaler&#x27;,\n",
" StandardScaler())]),\n",
" [&#x27;nb_tickets&#x27;, &#x27;nb_purchases&#x27;,\n",
" &#x27;total_amount&#x27;,\n",
" &#x27;nb_suppliers&#x27;,\n",
" &#x27;vente_internet_max&#x27;,\n",
" &#x27;purchase_date_min&#x27;,\n",
" &#x27;purchase_date_max&#x27;,\n",
" &#x27;time_between_purchase&#x27;,\n",
" &#x27;nb_tickets_internet&#x27;,\n",
" &#x27;nb_campaigns&#x27;,\n",
" &#x27;nb_campaigns_opened&#x27;]),\n",
" (&#x27;cat&#x27;,\n",
" Pipeline(steps=[(&#x27;onehot&#x27;,\n",
" OneHotEncoder(handle_unknown=&#x27;ignore&#x27;,\n",
" sparse_output=False))]),\n",
" [&#x27;opt_in&#x27;, &#x27;gender_male&#x27;,\n",
" &#x27;gender_female&#x27;])])),\n",
" (&#x27;LogisticRegression_cv&#x27;,\n",
" LogisticRegression(max_iter=5000, solver=&#x27;saga&#x27;))])</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-3\" type=\"checkbox\" ><label for=\"sk-estimator-id-3\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;preprocessor: ColumnTransformer<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.compose.ColumnTransformer.html\">?<span>Documentation for preprocessor: ColumnTransformer</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>ColumnTransformer(transformers=[(&#x27;num&#x27;,\n",
" Pipeline(steps=[(&#x27;scaler&#x27;, StandardScaler())]),\n",
" [&#x27;nb_tickets&#x27;, &#x27;nb_purchases&#x27;, &#x27;total_amount&#x27;,\n",
" &#x27;nb_suppliers&#x27;, &#x27;vente_internet_max&#x27;,\n",
" &#x27;purchase_date_min&#x27;, &#x27;purchase_date_max&#x27;,\n",
" &#x27;time_between_purchase&#x27;,\n",
" &#x27;nb_tickets_internet&#x27;, &#x27;nb_campaigns&#x27;,\n",
" &#x27;nb_campaigns_opened&#x27;]),\n",
" (&#x27;cat&#x27;,\n",
" Pipeline(steps=[(&#x27;onehot&#x27;,\n",
" OneHotEncoder(handle_unknown=&#x27;ignore&#x27;,\n",
" sparse_output=False))]),\n",
" [&#x27;opt_in&#x27;, &#x27;gender_male&#x27;, &#x27;gender_female&#x27;])])</pre></div> </div></div><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-4\" type=\"checkbox\" ><label for=\"sk-estimator-id-4\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">num</label><div class=\"sk-toggleable__content fitted\"><pre>[&#x27;nb_tickets&#x27;, &#x27;nb_purchases&#x27;, &#x27;total_amount&#x27;, &#x27;nb_suppliers&#x27;, &#x27;vente_internet_max&#x27;, &#x27;purchase_date_min&#x27;, &#x27;purchase_date_max&#x27;, &#x27;time_between_purchase&#x27;, &#x27;nb_tickets_internet&#x27;, &#x27;nb_campaigns&#x27;, &#x27;nb_campaigns_opened&#x27;]</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-5\" type=\"checkbox\" ><label for=\"sk-estimator-id-5\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;StandardScaler<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.preprocessing.StandardScaler.html\">?<span>Documentation for StandardScaler</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>StandardScaler()</pre></div> </div></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-6\" type=\"checkbox\" ><label for=\"sk-estimator-id-6\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">cat</label><div class=\"sk-toggleable__content fitted\"><pre>[&#x27;opt_in&#x27;, &#x27;gender_male&#x27;, &#x27;gender_female&#x27;]</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-7\" type=\"checkbox\" ><label for=\"sk-estimator-id-7\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;OneHotEncoder<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.preprocessing.OneHotEncoder.html\">?<span>Documentation for OneHotEncoder</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>OneHotEncoder(handle_unknown=&#x27;ignore&#x27;, sparse_output=False)</pre></div> </div></div></div></div></div></div></div></div></div><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-8\" type=\"checkbox\" ><label for=\"sk-estimator-id-8\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;LogisticRegression<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.linear_model.LogisticRegression.html\">?<span>Documentation for LogisticRegression</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>LogisticRegression(max_iter=5000, solver=&#x27;saga&#x27;)</pre></div> </div></div></div></div></div></div></div></div></div></div></div>"
],
"text/plain": [
"GridSearchCV(cv=3, error_score='raise',\n",
" estimator=Pipeline(steps=[('preprocessor',\n",
" ColumnTransformer(transformers=[('num',\n",
" Pipeline(steps=[('scaler',\n",
" StandardScaler())]),\n",
" ['nb_tickets',\n",
" 'nb_purchases',\n",
" 'total_amount',\n",
" 'nb_suppliers',\n",
" 'vente_internet_max',\n",
" 'purchase_date_min',\n",
" 'purchase_date_max',\n",
" 'time_between_purchase',\n",
" 'nb_tickets_internet',\n",
" 'nb_campaigns',\n",
" 'nb_...\n",
" 1.562500e-02, 3.125000e-02, 6.250000e-02, 1.250000e-01,\n",
" 2.500000e-01, 5.000000e-01, 1.000000e+00, 2.000000e+00,\n",
" 4.000000e+00, 8.000000e+00, 1.600000e+01, 3.200000e+01,\n",
" 6.400000e+01]),\n",
" 'LogisticRegression_cv__class_weight': ['balanced',\n",
" {0.0: 0.5837086520288036,\n",
" 1.0: 3.486549107420539}],\n",
" 'LogisticRegression_cv__penalty': ['l1', 'l2']},\n",
" scoring=make_scorer(recall_score, response_method='predict'))"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"logit_cv = load_model(\"sport\", \"LogisticRegression_cv\")\n",
"logit_cv"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "6f3e584d-c70d-4b45-b947-4414ff416e17",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>#sk-container-id-2 {\n",
" /* Definition of color scheme common for light and dark mode */\n",
" --sklearn-color-text: black;\n",
" --sklearn-color-line: gray;\n",
" /* Definition of color scheme for unfitted estimators */\n",
" --sklearn-color-unfitted-level-0: #fff5e6;\n",
" --sklearn-color-unfitted-level-1: #f6e4d2;\n",
" --sklearn-color-unfitted-level-2: #ffe0b3;\n",
" --sklearn-color-unfitted-level-3: chocolate;\n",
" /* Definition of color scheme for fitted estimators */\n",
" --sklearn-color-fitted-level-0: #f0f8ff;\n",
" --sklearn-color-fitted-level-1: #d4ebff;\n",
" --sklearn-color-fitted-level-2: #b3dbfd;\n",
" --sklearn-color-fitted-level-3: cornflowerblue;\n",
"\n",
" /* Specific color for light theme */\n",
" --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
" --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
" --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
" --sklearn-color-icon: #696969;\n",
"\n",
" @media (prefers-color-scheme: dark) {\n",
" /* Redefinition of color scheme for dark theme */\n",
" --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
" --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
" --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
" --sklearn-color-icon: #878787;\n",
" }\n",
"}\n",
"\n",
"#sk-container-id-2 {\n",
" color: var(--sklearn-color-text);\n",
"}\n",
"\n",
"#sk-container-id-2 pre {\n",
" padding: 0;\n",
"}\n",
"\n",
"#sk-container-id-2 input.sk-hidden--visually {\n",
" border: 0;\n",
" clip: rect(1px 1px 1px 1px);\n",
" clip: rect(1px, 1px, 1px, 1px);\n",
" height: 1px;\n",
" margin: -1px;\n",
" overflow: hidden;\n",
" padding: 0;\n",
" position: absolute;\n",
" width: 1px;\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-dashed-wrapped {\n",
" border: 1px dashed var(--sklearn-color-line);\n",
" margin: 0 0.4em 0.5em 0.4em;\n",
" box-sizing: border-box;\n",
" padding-bottom: 0.4em;\n",
" background-color: var(--sklearn-color-background);\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-container {\n",
" /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
" but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
" so we also need the `!important` here to be able to override the\n",
" default hidden behavior on the sphinx rendered scikit-learn.org.\n",
" See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
" display: inline-block !important;\n",
" position: relative;\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-text-repr-fallback {\n",
" display: none;\n",
"}\n",
"\n",
"div.sk-parallel-item,\n",
"div.sk-serial,\n",
"div.sk-item {\n",
" /* draw centered vertical line to link estimators */\n",
" background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
" background-size: 2px 100%;\n",
" background-repeat: no-repeat;\n",
" background-position: center center;\n",
"}\n",
"\n",
"/* Parallel-specific style estimator block */\n",
"\n",
"#sk-container-id-2 div.sk-parallel-item::after {\n",
" content: \"\";\n",
" width: 100%;\n",
" border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
" flex-grow: 1;\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-parallel {\n",
" display: flex;\n",
" align-items: stretch;\n",
" justify-content: center;\n",
" background-color: var(--sklearn-color-background);\n",
" position: relative;\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-parallel-item {\n",
" display: flex;\n",
" flex-direction: column;\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-parallel-item:first-child::after {\n",
" align-self: flex-end;\n",
" width: 50%;\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-parallel-item:last-child::after {\n",
" align-self: flex-start;\n",
" width: 50%;\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-parallel-item:only-child::after {\n",
" width: 0;\n",
"}\n",
"\n",
"/* Serial-specific style estimator block */\n",
"\n",
"#sk-container-id-2 div.sk-serial {\n",
" display: flex;\n",
" flex-direction: column;\n",
" align-items: center;\n",
" background-color: var(--sklearn-color-background);\n",
" padding-right: 1em;\n",
" padding-left: 1em;\n",
"}\n",
"\n",
"\n",
"/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
"clickable and can be expanded/collapsed.\n",
"- Pipeline and ColumnTransformer use this feature and define the default style\n",
"- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
"*/\n",
"\n",
"/* Pipeline and ColumnTransformer style (default) */\n",
"\n",
"#sk-container-id-2 div.sk-toggleable {\n",
" /* Default theme specific background. It is overwritten whether we have a\n",
" specific estimator or a Pipeline/ColumnTransformer */\n",
" background-color: var(--sklearn-color-background);\n",
"}\n",
"\n",
"/* Toggleable label */\n",
"#sk-container-id-2 label.sk-toggleable__label {\n",
" cursor: pointer;\n",
" display: block;\n",
" width: 100%;\n",
" margin-bottom: 0;\n",
" padding: 0.5em;\n",
" box-sizing: border-box;\n",
" text-align: center;\n",
"}\n",
"\n",
"#sk-container-id-2 label.sk-toggleable__label-arrow:before {\n",
" /* Arrow on the left of the label */\n",
" content: \"▸\";\n",
" float: left;\n",
" margin-right: 0.25em;\n",
" color: var(--sklearn-color-icon);\n",
"}\n",
"\n",
"#sk-container-id-2 label.sk-toggleable__label-arrow:hover:before {\n",
" color: var(--sklearn-color-text);\n",
"}\n",
"\n",
"/* Toggleable content - dropdown */\n",
"\n",
"#sk-container-id-2 div.sk-toggleable__content {\n",
" max-height: 0;\n",
" max-width: 0;\n",
" overflow: hidden;\n",
" text-align: left;\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-toggleable__content.fitted {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-toggleable__content pre {\n",
" margin: 0.2em;\n",
" border-radius: 0.25em;\n",
" color: var(--sklearn-color-text);\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-toggleable__content.fitted pre {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-fitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-2 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
" /* Expand drop-down */\n",
" max-height: 200px;\n",
" max-width: 100%;\n",
" overflow: auto;\n",
"}\n",
"\n",
"#sk-container-id-2 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
" content: \"▾\";\n",
"}\n",
"\n",
"/* Pipeline/ColumnTransformer-specific style */\n",
"\n",
"#sk-container-id-2 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
" color: var(--sklearn-color-text);\n",
" background-color: var(--sklearn-color-unfitted-level-2);\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
" background-color: var(--sklearn-color-fitted-level-2);\n",
"}\n",
"\n",
"/* Estimator-specific style */\n",
"\n",
"/* Colorize estimator box */\n",
"#sk-container-id-2 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-2);\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-2);\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-label label.sk-toggleable__label,\n",
"#sk-container-id-2 div.sk-label label {\n",
" /* The background is the default theme color */\n",
" color: var(--sklearn-color-text-on-default-background);\n",
"}\n",
"\n",
"/* On hover, darken the color of the background */\n",
"#sk-container-id-2 div.sk-label:hover label.sk-toggleable__label {\n",
" color: var(--sklearn-color-text);\n",
" background-color: var(--sklearn-color-unfitted-level-2);\n",
"}\n",
"\n",
"/* Label box, darken color on hover, fitted */\n",
"#sk-container-id-2 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
" color: var(--sklearn-color-text);\n",
" background-color: var(--sklearn-color-fitted-level-2);\n",
"}\n",
"\n",
"/* Estimator label */\n",
"\n",
"#sk-container-id-2 div.sk-label label {\n",
" font-family: monospace;\n",
" font-weight: bold;\n",
" display: inline-block;\n",
" line-height: 1.2em;\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-label-container {\n",
" text-align: center;\n",
"}\n",
"\n",
"/* Estimator-specific */\n",
"#sk-container-id-2 div.sk-estimator {\n",
" font-family: monospace;\n",
" border: 1px dotted var(--sklearn-color-border-box);\n",
" border-radius: 0.25em;\n",
" box-sizing: border-box;\n",
" margin-bottom: 0.5em;\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-estimator.fitted {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-0);\n",
"}\n",
"\n",
"/* on hover */\n",
"#sk-container-id-2 div.sk-estimator:hover {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-2);\n",
"}\n",
"\n",
"#sk-container-id-2 div.sk-estimator.fitted:hover {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-2);\n",
"}\n",
"\n",
"/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
"\n",
"/* Common style for \"i\" and \"?\" */\n",
"\n",
".sk-estimator-doc-link,\n",
"a:link.sk-estimator-doc-link,\n",
"a:visited.sk-estimator-doc-link {\n",
" float: right;\n",
" font-size: smaller;\n",
" line-height: 1em;\n",
" font-family: monospace;\n",
" background-color: var(--sklearn-color-background);\n",
" border-radius: 1em;\n",
" height: 1em;\n",
" width: 1em;\n",
" text-decoration: none !important;\n",
" margin-left: 1ex;\n",
" /* unfitted */\n",
" border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
" color: var(--sklearn-color-unfitted-level-1);\n",
"}\n",
"\n",
".sk-estimator-doc-link.fitted,\n",
"a:link.sk-estimator-doc-link.fitted,\n",
"a:visited.sk-estimator-doc-link.fitted {\n",
" /* fitted */\n",
" border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
" color: var(--sklearn-color-fitted-level-1);\n",
"}\n",
"\n",
"/* On hover */\n",
"div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
".sk-estimator-doc-link:hover,\n",
"div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
".sk-estimator-doc-link:hover {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-3);\n",
" color: var(--sklearn-color-background);\n",
" text-decoration: none;\n",
"}\n",
"\n",
"div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
".sk-estimator-doc-link.fitted:hover,\n",
"div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
".sk-estimator-doc-link.fitted:hover {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-3);\n",
" color: var(--sklearn-color-background);\n",
" text-decoration: none;\n",
"}\n",
"\n",
"/* Span, style for the box shown on hovering the info icon */\n",
".sk-estimator-doc-link span {\n",
" display: none;\n",
" z-index: 9999;\n",
" position: relative;\n",
" font-weight: normal;\n",
" right: .2ex;\n",
" padding: .5ex;\n",
" margin: .5ex;\n",
" width: min-content;\n",
" min-width: 20ex;\n",
" max-width: 50ex;\n",
" color: var(--sklearn-color-text);\n",
" box-shadow: 2pt 2pt 4pt #999;\n",
" /* unfitted */\n",
" background: var(--sklearn-color-unfitted-level-0);\n",
" border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
"}\n",
"\n",
".sk-estimator-doc-link.fitted span {\n",
" /* fitted */\n",
" background: var(--sklearn-color-fitted-level-0);\n",
" border: var(--sklearn-color-fitted-level-3);\n",
"}\n",
"\n",
".sk-estimator-doc-link:hover span {\n",
" display: block;\n",
"}\n",
"\n",
"/* \"?\"-specific style due to the `<a>` HTML tag */\n",
"\n",
"#sk-container-id-2 a.estimator_doc_link {\n",
" float: right;\n",
" font-size: 1rem;\n",
" line-height: 1em;\n",
" font-family: monospace;\n",
" background-color: var(--sklearn-color-background);\n",
" border-radius: 1rem;\n",
" height: 1rem;\n",
" width: 1rem;\n",
" text-decoration: none;\n",
" /* unfitted */\n",
" color: var(--sklearn-color-unfitted-level-1);\n",
" border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
"}\n",
"\n",
"#sk-container-id-2 a.estimator_doc_link.fitted {\n",
" /* fitted */\n",
" border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
" color: var(--sklearn-color-fitted-level-1);\n",
"}\n",
"\n",
"/* On hover */\n",
"#sk-container-id-2 a.estimator_doc_link:hover {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-3);\n",
" color: var(--sklearn-color-background);\n",
" text-decoration: none;\n",
"}\n",
"\n",
"#sk-container-id-2 a.estimator_doc_link.fitted:hover {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-3);\n",
"}\n",
"</style><div id=\"sk-container-id-2\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>GridSearchCV(cv=3, error_score=&#x27;raise&#x27;,\n",
" estimator=Pipeline(steps=[(&#x27;preprocessor&#x27;,\n",
" ColumnTransformer(transformers=[(&#x27;num&#x27;,\n",
" Pipeline(steps=[(&#x27;scaler&#x27;,\n",
" StandardScaler())]),\n",
" [&#x27;nb_tickets&#x27;,\n",
" &#x27;nb_purchases&#x27;,\n",
" &#x27;total_amount&#x27;,\n",
" &#x27;nb_suppliers&#x27;,\n",
" &#x27;vente_internet_max&#x27;,\n",
" &#x27;purchase_date_min&#x27;,\n",
" &#x27;purchase_date_max&#x27;,\n",
" &#x27;time_between_purchase&#x27;,\n",
" &#x27;nb_tickets_internet&#x27;,\n",
" &#x27;nb_campaigns&#x27;,\n",
" &#x27;nb_...\n",
" 1.562500e-02, 3.125000e-02, 6.250000e-02, 1.250000e-01,\n",
" 2.500000e-01, 5.000000e-01, 1.000000e+00, 2.000000e+00,\n",
" 4.000000e+00, 8.000000e+00, 1.600000e+01, 3.200000e+01,\n",
" 6.400000e+01]),\n",
" &#x27;LogisticRegression_cv__class_weight&#x27;: [&#x27;balanced&#x27;,\n",
" {0.0: 0.5837086520288036,\n",
" 1.0: 3.486549107420539}],\n",
" &#x27;LogisticRegression_cv__penalty&#x27;: [&#x27;l1&#x27;, &#x27;l2&#x27;]},\n",
" scoring=make_scorer(recall_score, response_method=&#x27;predict&#x27;))</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-9\" type=\"checkbox\" ><label for=\"sk-estimator-id-9\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;&nbsp;GridSearchCV<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.model_selection.GridSearchCV.html\">?<span>Documentation for GridSearchCV</span></a><span class=\"sk-estimator-doc-link fitted\">i<span>Fitted</span></span></label><div class=\"sk-toggleable__content fitted\"><pre>GridSearchCV(cv=3, error_score=&#x27;raise&#x27;,\n",
" estimator=Pipeline(steps=[(&#x27;preprocessor&#x27;,\n",
" ColumnTransformer(transformers=[(&#x27;num&#x27;,\n",
" Pipeline(steps=[(&#x27;scaler&#x27;,\n",
" StandardScaler())]),\n",
" [&#x27;nb_tickets&#x27;,\n",
" &#x27;nb_purchases&#x27;,\n",
" &#x27;total_amount&#x27;,\n",
" &#x27;nb_suppliers&#x27;,\n",
" &#x27;vente_internet_max&#x27;,\n",
" &#x27;purchase_date_min&#x27;,\n",
" &#x27;purchase_date_max&#x27;,\n",
" &#x27;time_between_purchase&#x27;,\n",
" &#x27;nb_tickets_internet&#x27;,\n",
" &#x27;nb_campaigns&#x27;,\n",
" &#x27;nb_...\n",
" 1.562500e-02, 3.125000e-02, 6.250000e-02, 1.250000e-01,\n",
" 2.500000e-01, 5.000000e-01, 1.000000e+00, 2.000000e+00,\n",
" 4.000000e+00, 8.000000e+00, 1.600000e+01, 3.200000e+01,\n",
" 6.400000e+01]),\n",
" &#x27;LogisticRegression_cv__class_weight&#x27;: [&#x27;balanced&#x27;,\n",
" {0.0: 0.5837086520288036,\n",
" 1.0: 3.486549107420539}],\n",
" &#x27;LogisticRegression_cv__penalty&#x27;: [&#x27;l1&#x27;, &#x27;l2&#x27;]},\n",
" scoring=make_scorer(recall_score, response_method=&#x27;predict&#x27;))</pre></div> </div></div><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-10\" type=\"checkbox\" ><label for=\"sk-estimator-id-10\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">estimator: Pipeline</label><div class=\"sk-toggleable__content fitted\"><pre>Pipeline(steps=[(&#x27;preprocessor&#x27;,\n",
" ColumnTransformer(transformers=[(&#x27;num&#x27;,\n",
" Pipeline(steps=[(&#x27;scaler&#x27;,\n",
" StandardScaler())]),\n",
" [&#x27;nb_tickets&#x27;, &#x27;nb_purchases&#x27;,\n",
" &#x27;total_amount&#x27;,\n",
" &#x27;nb_suppliers&#x27;,\n",
" &#x27;vente_internet_max&#x27;,\n",
" &#x27;purchase_date_min&#x27;,\n",
" &#x27;purchase_date_max&#x27;,\n",
" &#x27;time_between_purchase&#x27;,\n",
" &#x27;nb_tickets_internet&#x27;,\n",
" &#x27;nb_campaigns&#x27;,\n",
" &#x27;nb_campaigns_opened&#x27;]),\n",
" (&#x27;cat&#x27;,\n",
" Pipeline(steps=[(&#x27;onehot&#x27;,\n",
" OneHotEncoder(handle_unknown=&#x27;ignore&#x27;,\n",
" sparse_output=False))]),\n",
" [&#x27;opt_in&#x27;, &#x27;gender_male&#x27;,\n",
" &#x27;gender_female&#x27;])])),\n",
" (&#x27;LogisticRegression_cv&#x27;,\n",
" LogisticRegression(max_iter=5000, solver=&#x27;saga&#x27;))])</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-11\" type=\"checkbox\" ><label for=\"sk-estimator-id-11\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;preprocessor: ColumnTransformer<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.compose.ColumnTransformer.html\">?<span>Documentation for preprocessor: ColumnTransformer</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>ColumnTransformer(transformers=[(&#x27;num&#x27;,\n",
" Pipeline(steps=[(&#x27;scaler&#x27;, StandardScaler())]),\n",
" [&#x27;nb_tickets&#x27;, &#x27;nb_purchases&#x27;, &#x27;total_amount&#x27;,\n",
" &#x27;nb_suppliers&#x27;, &#x27;vente_internet_max&#x27;,\n",
" &#x27;purchase_date_min&#x27;, &#x27;purchase_date_max&#x27;,\n",
" &#x27;time_between_purchase&#x27;,\n",
" &#x27;nb_tickets_internet&#x27;, &#x27;nb_campaigns&#x27;,\n",
" &#x27;nb_campaigns_opened&#x27;]),\n",
" (&#x27;cat&#x27;,\n",
" Pipeline(steps=[(&#x27;onehot&#x27;,\n",
" OneHotEncoder(handle_unknown=&#x27;ignore&#x27;,\n",
" sparse_output=False))]),\n",
" [&#x27;opt_in&#x27;, &#x27;gender_male&#x27;, &#x27;gender_female&#x27;])])</pre></div> </div></div><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-12\" type=\"checkbox\" ><label for=\"sk-estimator-id-12\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">num</label><div class=\"sk-toggleable__content fitted\"><pre>[&#x27;nb_tickets&#x27;, &#x27;nb_purchases&#x27;, &#x27;total_amount&#x27;, &#x27;nb_suppliers&#x27;, &#x27;vente_internet_max&#x27;, &#x27;purchase_date_min&#x27;, &#x27;purchase_date_max&#x27;, &#x27;time_between_purchase&#x27;, &#x27;nb_tickets_internet&#x27;, &#x27;nb_campaigns&#x27;, &#x27;nb_campaigns_opened&#x27;]</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-13\" type=\"checkbox\" ><label for=\"sk-estimator-id-13\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;StandardScaler<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.preprocessing.StandardScaler.html\">?<span>Documentation for StandardScaler</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>StandardScaler()</pre></div> </div></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-14\" type=\"checkbox\" ><label for=\"sk-estimator-id-14\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">cat</label><div class=\"sk-toggleable__content fitted\"><pre>[&#x27;opt_in&#x27;, &#x27;gender_male&#x27;, &#x27;gender_female&#x27;]</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-15\" type=\"checkbox\" ><label for=\"sk-estimator-id-15\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;OneHotEncoder<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.preprocessing.OneHotEncoder.html\">?<span>Documentation for OneHotEncoder</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>OneHotEncoder(handle_unknown=&#x27;ignore&#x27;, sparse_output=False)</pre></div> </div></div></div></div></div></div></div></div></div><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-16\" type=\"checkbox\" ><label for=\"sk-estimator-id-16\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;LogisticRegression<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.linear_model.LogisticRegression.html\">?<span>Documentation for LogisticRegression</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>LogisticRegression(max_iter=5000, solver=&#x27;saga&#x27;)</pre></div> </div></div></div></div></div></div></div></div></div></div></div>"
],
"text/plain": [
"GridSearchCV(cv=3, error_score='raise',\n",
" estimator=Pipeline(steps=[('preprocessor',\n",
" ColumnTransformer(transformers=[('num',\n",
" Pipeline(steps=[('scaler',\n",
" StandardScaler())]),\n",
" ['nb_tickets',\n",
" 'nb_purchases',\n",
" 'total_amount',\n",
" 'nb_suppliers',\n",
" 'vente_internet_max',\n",
" 'purchase_date_min',\n",
" 'purchase_date_max',\n",
" 'time_between_purchase',\n",
" 'nb_tickets_internet',\n",
" 'nb_campaigns',\n",
" 'nb_...\n",
" 1.562500e-02, 3.125000e-02, 6.250000e-02, 1.250000e-01,\n",
" 2.500000e-01, 5.000000e-01, 1.000000e+00, 2.000000e+00,\n",
" 4.000000e+00, 8.000000e+00, 1.600000e+01, 3.200000e+01,\n",
" 6.400000e+01]),\n",
" 'LogisticRegression_cv__class_weight': ['balanced',\n",
" {0.0: 0.5837086520288036,\n",
" 1.0: 3.486549107420539}],\n",
" 'LogisticRegression_cv__penalty': ['l1', 'l2']},\n",
" scoring=make_scorer(recall_score, response_method='predict'))"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"logit_cv"
]
},
{
"cell_type": "markdown",
"id": "006819e7-e9c5-48d9-85ee-aa43d5e4c9c2",
"metadata": {},
"source": [
"## Quartile clustering"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "018d8ff4-3436-4eec-8507-d1a265cbabf1",
"metadata": {},
"outputs": [],
"source": [
"y_pred = logit_cv.predict(X_test)\n",
"y_pred_prob = logit_cv.predict_proba(X_test)[:, 1]"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "846f53b9-73c2-4a8b-9d9e-f11bf59ce9ba",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_519/375041546.py:3: SettingWithCopyWarning: \n",
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
"Try using .loc[row_indexer,col_indexer] = value instead\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
" X_test_segment[\"has_purchased\"] = y_test\n",
"/tmp/ipykernel_519/375041546.py:4: SettingWithCopyWarning: \n",
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
"Try using .loc[row_indexer,col_indexer] = value instead\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
" X_test_segment[\"has_purchased_estim\"] = y_pred\n",
"/tmp/ipykernel_519/375041546.py:5: SettingWithCopyWarning: \n",
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
"Try using .loc[row_indexer,col_indexer] = value instead\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
" X_test_segment[\"score\"] = y_pred_prob\n",
"/tmp/ipykernel_519/375041546.py:6: SettingWithCopyWarning: \n",
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
"Try using .loc[row_indexer,col_indexer] = value instead\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
" X_test_segment[\"quartile\"] = np.where(X_test['score']<0.25, '1',\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>nb_tickets</th>\n",
" <th>nb_purchases</th>\n",
" <th>total_amount</th>\n",
" <th>nb_suppliers</th>\n",
" <th>vente_internet_max</th>\n",
" <th>purchase_date_min</th>\n",
" <th>purchase_date_max</th>\n",
" <th>time_between_purchase</th>\n",
" <th>nb_tickets_internet</th>\n",
" <th>fidelity</th>\n",
" <th>...</th>\n",
" <th>opt_in</th>\n",
" <th>gender_female</th>\n",
" <th>gender_male</th>\n",
" <th>gender_other</th>\n",
" <th>nb_campaigns</th>\n",
" <th>nb_campaigns_opened</th>\n",
" <th>has_purchased</th>\n",
" <th>has_purchased_estim</th>\n",
" <th>score</th>\n",
" <th>quartile</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>4.0</td>\n",
" <td>1.0</td>\n",
" <td>100.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>5.177187</td>\n",
" <td>5.177187</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>False</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.657671</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>55.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>426.265613</td>\n",
" <td>426.265613</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>2</td>\n",
" <td>...</td>\n",
" <td>True</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>0.266538</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>17.0</td>\n",
" <td>1.0</td>\n",
" <td>80.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>436.033437</td>\n",
" <td>436.033437</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>2</td>\n",
" <td>...</td>\n",
" <td>True</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.214668</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>4.0</td>\n",
" <td>1.0</td>\n",
" <td>120.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>5.196412</td>\n",
" <td>5.196412</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>False</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.657770</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>34.0</td>\n",
" <td>2.0</td>\n",
" <td>416.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>478.693148</td>\n",
" <td>115.631470</td>\n",
" <td>363.061678</td>\n",
" <td>0.0</td>\n",
" <td>4</td>\n",
" <td>...</td>\n",
" <td>False</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>0.894173</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>2.0</td>\n",
" <td>1.0</td>\n",
" <td>60.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>5.140069</td>\n",
" <td>5.140069</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>False</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.717482</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>5.0</td>\n",
" <td>1.0</td>\n",
" <td>61.0</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>105.053773</td>\n",
" <td>105.053773</td>\n",
" <td>0.000000</td>\n",
" <td>5.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>False</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.541855</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>4.0</td>\n",
" <td>1.0</td>\n",
" <td>80.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>63.206030</td>\n",
" <td>63.206030</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>True</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.461164</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>10.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>44.698090</td>\n",
" <td>44.698090</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>True</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.310828</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>3.0</td>\n",
" <td>3.0</td>\n",
" <td>165.0</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>266.012106</td>\n",
" <td>258.012106</td>\n",
" <td>8.000000</td>\n",
" <td>3.0</td>\n",
" <td>2</td>\n",
" <td>...</td>\n",
" <td>False</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.452877</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>10 rows × 21 columns</p>\n",
"</div>"
],
"text/plain": [
" nb_tickets nb_purchases total_amount nb_suppliers vente_internet_max \\\n",
"0 4.0 1.0 100.0 1.0 0.0 \n",
"1 1.0 1.0 55.0 1.0 0.0 \n",
"2 17.0 1.0 80.0 1.0 0.0 \n",
"3 4.0 1.0 120.0 1.0 0.0 \n",
"4 34.0 2.0 416.0 1.0 0.0 \n",
"5 2.0 1.0 60.0 1.0 0.0 \n",
"6 5.0 1.0 61.0 1.0 1.0 \n",
"7 4.0 1.0 80.0 1.0 0.0 \n",
"8 1.0 1.0 10.0 1.0 0.0 \n",
"9 3.0 3.0 165.0 1.0 1.0 \n",
"\n",
" purchase_date_min purchase_date_max time_between_purchase \\\n",
"0 5.177187 5.177187 0.000000 \n",
"1 426.265613 426.265613 0.000000 \n",
"2 436.033437 436.033437 0.000000 \n",
"3 5.196412 5.196412 0.000000 \n",
"4 478.693148 115.631470 363.061678 \n",
"5 5.140069 5.140069 0.000000 \n",
"6 105.053773 105.053773 0.000000 \n",
"7 63.206030 63.206030 0.000000 \n",
"8 44.698090 44.698090 0.000000 \n",
"9 266.012106 258.012106 8.000000 \n",
"\n",
" nb_tickets_internet fidelity ... opt_in gender_female gender_male \\\n",
"0 0.0 1 ... False 1 0 \n",
"1 0.0 2 ... True 0 1 \n",
"2 0.0 2 ... True 1 0 \n",
"3 0.0 1 ... False 1 0 \n",
"4 0.0 4 ... False 1 0 \n",
"5 0.0 1 ... False 0 1 \n",
"6 5.0 1 ... False 0 0 \n",
"7 0.0 1 ... True 0 1 \n",
"8 0.0 1 ... True 0 0 \n",
"9 3.0 2 ... False 0 0 \n",
"\n",
" gender_other nb_campaigns nb_campaigns_opened has_purchased \\\n",
"0 0 0.0 0.0 0.0 \n",
"1 0 0.0 0.0 1.0 \n",
"2 0 0.0 0.0 0.0 \n",
"3 0 0.0 0.0 0.0 \n",
"4 0 0.0 0.0 1.0 \n",
"5 0 0.0 0.0 0.0 \n",
"6 1 0.0 0.0 0.0 \n",
"7 0 0.0 0.0 0.0 \n",
"8 1 0.0 0.0 0.0 \n",
"9 1 0.0 0.0 0.0 \n",
"\n",
" has_purchased_estim score quartile \n",
"0 1.0 0.657671 3 \n",
"1 0.0 0.266538 2 \n",
"2 0.0 0.214668 1 \n",
"3 1.0 0.657770 3 \n",
"4 1.0 0.894173 4 \n",
"5 1.0 0.717482 3 \n",
"6 1.0 0.541855 3 \n",
"7 0.0 0.461164 2 \n",
"8 0.0 0.310828 2 \n",
"9 0.0 0.452877 2 \n",
"\n",
"[10 rows x 21 columns]"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X_test_segment = X_test\n",
"\n",
"X_test_segment[\"has_purchased\"] = y_test\n",
"X_test_segment[\"has_purchased_estim\"] = y_pred\n",
"X_test_segment[\"score\"] = y_pred_prob\n",
"X_test_segment[\"quartile\"] = np.where(X_test['score']<0.25, '1',\n",
" np.where(X_test['score']<0.5, '2',\n",
" np.where(X_test['score']<0.75, '3', '4')))\n",
"X_test_segment.head(10)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0916f099-3faa-4c47-9b60-d1ee797b3c9d",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "ad16b8ab-7e01-404b-971e-866e9b9d5aa4",
"metadata": {},
"source": [
"## definition of functions to compute the bias of scores and adjust it \n",
"\n",
"Le biais est calculé de la façon suivante. \n",
"En notant $\\hat{p(x_i)}$ le score calculé (estimé par la modélisation) et $p(x_i)$ le vrai score (sans biais), et $\\beta$ le logarithme du biais, on a : \\\n",
"$\\ln{\\frac{\\hat{p(x_i)}}{1-\\hat{p(x_i)}}} = \\beta + \\ln{\\frac{p(x_i)}{1-p(x_i)}}$ \\\n",
"$ \\frac{\\hat{p(x_i)}}{1-\\hat{p(x_i)}} = \\exp(\\beta) . \\frac{p(x_i)}{1-p(x_i)} $ , soit : \\\n",
"$p(x_i) = {\\frac{\\frac{\\hat{p(x_i)}}{1-\\hat{p(x_i)}}}{B+\\frac{\\hat{p(x_i)}}{1-\\hat{p(x_i)}}}}$ \\\n",
"Ce qu'on appelle biais et qu'on estime dans le code par la suite est : $B=\\exp(\\beta) $. Les probabilités ne sont donc pas biaisées si $B=1$. Il y a surestimation si $B>1$. \n",
"\n",
"On cherche le B qui permette d'ajuster les probabilités de telle sorte que la somme des scores soit égale à la somme des y_has_purchased. Cela revient à résoudre : \n",
"\n",
"\\begin{equation}\n",
"\\sum_{i}{\\frac{\\frac{\\hat{p(x_i)}}{1-\\hat{p(x_i)}}}{B+\\frac{\\hat{p(x_i)}}{1-\\hat{p(x_i)}}}} = \\sum_{i}{Y_i}\n",
"\\end{equation}\n",
"\n",
"C'est ce que fait la fonction find_bias. \n",
"\n",
"Note sur les notations : \\\n",
"$\\hat{p(x_i)}$ correspond à ce qu'on appelle le score et $p(x_i)$ à ce qu'on appellera le score adjusted"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "f0379536-a6c5-4b16-bde5-d0319ec1b140",
"metadata": {},
"outputs": [],
"source": [
"# compute adjusted score from odd ratios (cf formula above)\n",
"def adjusted_score(odd_ratio, bias) :\n",
" adjusted_score = odd_ratio/(bias+odd_ratio)\n",
" return adjusted_score"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "32a0dfd0-f49d-4785-a56f-706d381bfe41",
"metadata": {},
"outputs": [],
"source": [
"# when the score is 1 we cannot compute the odd ratio, so we adjust scores equal to 1\n",
"# we set the second best score instead\n",
"\n",
"def adjust_score_1(score) :\n",
" second_best_score = np.array([element for element in score if element !=1]).max()\n",
" new_score = np.array([element if element!=1 else second_best_score for element in score]) \n",
" return new_score"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "2dff1def-02df-413e-afce-b4aeaf7752b6",
"metadata": {},
"outputs": [],
"source": [
"def odd_ratio(score) :\n",
" return score / (1 - score)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "683d71fc-7442-4028-869c-49c57592d6e9",
"metadata": {},
"outputs": [],
"source": [
"# definition of a function that automatically detects the bias\n",
"\n",
"def find_bias(odd_ratios, y_objective, initial_guess=6) :\n",
" \"\"\"\n",
" results = minimize(lambda bias : (sum([adjusted_score(element, bias) for element in list(odd_ratios)]) - y_objective)**2 ,\n",
" initial_guess , method = \"BFGS\")\n",
"\n",
" estimated_bias = results.x[0]\n",
" \"\"\"\n",
"\n",
" # faster method\n",
" bias_estimated = fsolve(lambda bias : sum([adjusted_score(element, bias) for element in list(odd_ratios)]) - y_objective, x0=6)\n",
" \n",
" return bias_estimated[0]"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "781b0d40-c954-4c54-830a-e709c8667328",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"6.172331113516847"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# computation with the function defined\n",
"\n",
"bias_test_set = find_bias(odd_ratios = odd_ratio(adjust_score_1(X_test_segment[\"score\"])), \n",
" y_objective = y_test[\"y_has_purchased\"].sum(),\n",
" initial_guess=6)\n",
"bias_test_set"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "248cb862-418e-4767-9933-70c4885ecf40",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"6.070461139075353"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# comparison with bias of the train set\n",
"X_train_score = logit_cv.predict_proba(X_train)[:, 1]\n",
"\n",
"bias_train_set = find_bias(odd_ratios = odd_ratio(adjust_score_1(X_train_score)), \n",
" y_objective = y_train[\"y_has_purchased\"].sum(),\n",
" initial_guess=6)\n",
"bias_train_set"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "fff6cbe6-7bb3-4732-9b81-b9ac5383bbcf",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"betâ test - betâ train = 0.016642008368292337\n"
]
}
],
"source": [
"print(\"betâ test - betâ train = \",np.log(bias_test_set/bias_train_set))"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "f506870d-4a8a-4b2c-8f0b-e0789080b20c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"mean absolute erreur 0.001409799678121875\n"
]
}
],
"source": [
"# impact of considering a bias computed on train set instead of test set - totally neglectable\n",
"\n",
"score_adjusted_test = adjusted_score(odd_ratio(adjust_score_1(X_test_segment[\"score\"])), bias = bias_test_set)\n",
"score_adjusted_train = adjusted_score(odd_ratio(adjust_score_1(X_test_segment[\"score\"])), bias = bias_train_set)\n",
"\n",
"print(\"mean absolute erreur\",abs(score_adjusted_test-score_adjusted_train).mean())"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "8213d0e4-063b-49fa-90b7-677fc34f4c01",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_519/1825363704.py:7: SettingWithCopyWarning: \n",
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
"Try using .loc[row_indexer,col_indexer] = value instead\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
" X_test_segment[\"score_adjusted\"] = score_adjusted_train\n"
]
}
],
"source": [
"# adjust scores accordingly \n",
"\n",
"# X_test_segment[\"score_adjusted\"] = adjusted_score(odd_ratio(adjust_score_1(X_test_segment[\"score\"])), bias = bias_test_set)\n",
"\n",
"# actually, we are not supposed to have X_test, so the biais is estimated on X_train\n",
"# X_test_segment[\"score_adjusted\"] = adjusted_score(odd_ratio(adjust_score_1(X_test_segment[\"score\"])), bias = bias_train_set)\n",
"X_test_segment[\"score_adjusted\"] = score_adjusted_train"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "834d3723-2e72-4c65-9c62-e2d595c69461",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"MSE for score : 0.15494387585189107\n",
"MSE for ajusted score : 0.08851697393139933\n",
"sum of y_has_purchased : 13690.0\n",
"sum of adjusted scores : 13825.476109871417\n"
]
}
],
"source": [
"# check \n",
"\n",
"MSE_score = ((X_test_segment[\"score\"]-X_test_segment[\"has_purchased\"])**2).mean()\n",
"MSE_ajusted_score = ((X_test_segment[\"score_adjusted\"]-X_test_segment[\"has_purchased\"])**2).mean()\n",
"print(f\"MSE for score : {MSE_score}\")\n",
"print(f\"MSE for ajusted score : {MSE_ajusted_score}\")\n",
"\n",
"print(\"sum of y_has_purchased :\",y_test[\"y_has_purchased\"].sum())\n",
"print(\"sum of adjusted scores :\", X_test_segment[\"score_adjusted\"].sum())"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "9f30a4dd-a9d8-405a-a7d5-5324ae88cf70",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"MAE for score : 0.32116357895490416\n",
"MAE for adjusted score : 0.17359227315595824\n"
]
}
],
"source": [
"# mean absolute error - divided by 2 with out method\n",
"\n",
"MAE_score = abs(X_test_segment[\"score\"]-X_test_segment[\"has_purchased\"]).mean()\n",
"MAE_ajusted_score = abs(X_test_segment[\"score_adjusted\"]-X_test_segment[\"has_purchased\"]).mean()\n",
"print(f\"MAE for score : {MAE_score}\")\n",
"print(f\"MAE for adjusted score : {MAE_ajusted_score}\")"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "6f9396db-e213-408c-a596-eaeec3bc79f3",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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1qxZE/Pnz0fr1q3x7rvv4s8//8SBAwegofE8YuzcuRPvvvsuPv74Y9jb22PKlCnSKFirVq2wfft2BAcHw8HBAV988QVmz54tOwm8OM2aNUN4eDhu3LiB9u3bo2XLlpgxYwYsLS1LXO5V8WdUyhF/RqUQ/owKEZXCv+lnVAq7du0aGjdujBs3blT4V07/FuXxMyocaSIiIqpEKSkp2LFjB4yMjKQRH6qaeCI4ERFRJRoxYgSio6OxatUq6OrqVnZzqAQMTURERJVo9+7dld0EUohfzxEREREpwNBERERVCq9PotehPI4rhiYiIqoStLW1AQBPnjyp5JbQm6jguCo4zsqC5zQREVGVoKmpiVq1aiE5ORkAoK+vX+QnNohKSwiBJ0+eIDk5GbVq1SrxTuMvw9BERERVhoWFBQBIwYmovNSqVUs6vsqKoYmIiKoMlUoFS0tLmJmZFfmBWqKy0tbWfqURpgIMTUREVOVoamqWy4ccUXniieBERERECjA0ERERESnA0ERERESkAEMTERERkQIMTUREREQKMDQRERERKcDQRERERKQAQxMRERGRAgxNRERERAowNBEREREpwNBEREREpABDExEREZECDE1ERERECjA0ERERESnA0ERERESkAEMTERERkQIMTUREREQKMDQRERERKcDQRERERKQAQxMRERGRAgxNRERERAowNBEREREpwNBEREREpABDExEREZECDE1EREREClRqaAoKCoJKpZI9LCwspPlCCAQFBcHKygp6enro2LEjrly5IltHdnY2xo8fDxMTExgYGKBPnz64e/eurCY1NRXe3t5Qq9VQq9Xw9vZGWlqarObOnTvo3bs3DAwMYGJiAj8/P+Tk5Ly2fSciIqLqpdJHmpo2bYrExETpcenSJWneggULsGTJEqxcuRJRUVGwsLBAt27d8OjRI6nG398fu3fvRnBwMCIiIvD48WN4enoiLy9PqvHy8kJMTAxCQkIQEhKCmJgYeHt7S/Pz8vLQq1cvZGZmIiIiAsHBwdi5cycCAgIqphOIiIioytOq9AZoaclGlwoIIbBs2TJMnz4d/fv3BwBs3LgR5ubm2Lp1K0aNGoX09HT88MMP2LRpE7p27QoA2Lx5M6ytrXHo0CF4eHggLi4OISEhOHXqFJydnQEAa9euhYuLC65duwY7OzuEhoYiNjYWCQkJsLKy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Vq1aVdlNIyIiokrG0PT/5eTkIDo6Gu7u7rLp7u7uiIyMrKRWERERUVXBq+f+v7///ht5eXkwNzeXTTc3N0dSUlKxy2RnZyM7O1t6np6eDgDIyMgo/wY+yX55TTnIfJpTIdshIiIqrdfy+fqP9QohSqxjaCpEpVLJngshikwrMG/ePMyaNavIdGtr69fSNiIion+1qdtf6+ofPXoEtVr9wvkMTf+fiYkJNDU1i4wqJScnFxl9KjBt2jRMmjRJep6fn4+UlBQYGxu/MGi9TEZGBqytrZGQkAAjI6MyrYOUYV9XHPZ1xWJ/Vxz2dcV5nX0thMCjR49gZWVVYh1D0/+no6MDJycnhIWF4f3335emh4WFoW/fvsUuo6urC11dXdm0WrVqlUt7jIyM+AdYQdjXFYd9XbHY3xWHfV1xXldflzTCVICh6R8mTZoEb29vtG7dGi4uLvjuu+9w584djB49urKbRkRERJWMoekfBg0ahIcPH2L27NlITEyEg4MDDhw4gPr161d204iIiKiSMTQV4uvrC19f30rbvq6uLmbOnFnkaz8qf+zrisO+rljs74rDvq44VaGvVeJl19cREREREW9uSURERKQEQxMRERGRAgxNRERERAowNBEREREpwNBUCb799lvY2NigRo0acHJywvHjx0usDw8Ph5OTE2rUqIGGDRti9erVFdTS6q80fb1r1y5069YNpqamMDIygouLC3777bcKbG31VtrjusCJEyegpaWFFi1avN4GvkFK29fZ2dmYPn066tevD11dXbz99ttYt25dBbW2+ittf2/ZsgXNmzeHvr4+LC0tMWzYMDx8+LCCWlt9/f777+jduzesrKygUqmwZ8+ely5T4Z+PgipUcHCw0NbWFmvXrhWxsbFiwoQJwsDAQNy+fbvY+lu3bgl9fX0xYcIEERsbK9auXSu0tbXFjh07Krjl1U9p+3rChAli/vz54syZM+L69eti2rRpQltbW5w7d66CW179lLavC6SlpYmGDRsKd3d30bx584ppbDVXlr7u06ePcHZ2FmFhYSI+Pl6cPn1anDhxogJbXX2Vtr+PHz8uNDQ0xPLly8WtW7fE8ePHRdOmTUW/fv0quOXVz4EDB8T06dPFzp07BQCxe/fuEusr4/ORoamCtWnTRowePVo2rXHjxuLzzz8vtn7KlCmicePGsmmjRo0Sbdu2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",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# visualization\n",
"\n",
"# histogramme des probas et des probas ajustées\n",
"\n",
"def plot_hist_scores(df, score, score_adjusted) :\n",
"\n",
" plt.figure()\n",
" plt.hist(df[score], label = \"score\", alpha=0.6)\n",
" plt.hist(df[score_adjusted], label=\"adjusted score\", alpha=0.6)\n",
" plt.legend()\n",
" plt.xlabel(\"probability of a future purchase\")\n",
" plt.ylabel(\"count\")\n",
" plt.title(\"Comparison between score and adjusted score\")\n",
" plt.show()\n",
"\n",
"plot_hist_scores(X_test_segment, score = \"score\", score_adjusted = \"score_adjusted\")"
]
},
{
"cell_type": "markdown",
"id": "e6fae260-fab8-4f51-90dc-9b6d7314c77b",
"metadata": {},
"source": [
"## Compute number of tickets and CA by segment with the recalibrated score"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "c618cebc-c295-47f7-bd76-b7e18778a17c",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>nb_tickets</th>\n",
" <th>nb_purchases</th>\n",
" <th>total_amount</th>\n",
" <th>nb_suppliers</th>\n",
" <th>vente_internet_max</th>\n",
" <th>purchase_date_min</th>\n",
" <th>purchase_date_max</th>\n",
" <th>time_between_purchase</th>\n",
" <th>nb_tickets_internet</th>\n",
" <th>fidelity</th>\n",
" <th>...</th>\n",
" <th>gender_female</th>\n",
" <th>gender_male</th>\n",
" <th>gender_other</th>\n",
" <th>nb_campaigns</th>\n",
" <th>nb_campaigns_opened</th>\n",
" <th>has_purchased</th>\n",
" <th>has_purchased_estim</th>\n",
" <th>score</th>\n",
" <th>quartile</th>\n",
" <th>score_adjusted</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>4.0</td>\n",
" <td>1.0</td>\n",
" <td>100.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>5.177187</td>\n",
" <td>5.177187</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.657671</td>\n",
" <td>3</td>\n",
" <td>0.240397</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>55.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>426.265613</td>\n",
" <td>426.265613</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>2</td>\n",
" <td>...</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>0.266538</td>\n",
" <td>2</td>\n",
" <td>0.056482</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>17.0</td>\n",
" <td>1.0</td>\n",
" <td>80.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>436.033437</td>\n",
" <td>436.033437</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>2</td>\n",
" <td>...</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.214668</td>\n",
" <td>1</td>\n",
" <td>0.043089</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>4.0</td>\n",
" <td>1.0</td>\n",
" <td>120.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>5.196412</td>\n",
" <td>5.196412</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.657770</td>\n",
" <td>3</td>\n",
" <td>0.240478</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>34.0</td>\n",
" <td>2.0</td>\n",
" <td>416.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>478.693148</td>\n",
" <td>115.631470</td>\n",
" <td>363.061678</td>\n",
" <td>0.0</td>\n",
" <td>4</td>\n",
" <td>...</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>0.894173</td>\n",
" <td>4</td>\n",
" <td>0.581920</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>5 rows × 22 columns</p>\n",
"</div>"
],
"text/plain": [
" nb_tickets nb_purchases total_amount nb_suppliers vente_internet_max \\\n",
"0 4.0 1.0 100.0 1.0 0.0 \n",
"1 1.0 1.0 55.0 1.0 0.0 \n",
"2 17.0 1.0 80.0 1.0 0.0 \n",
"3 4.0 1.0 120.0 1.0 0.0 \n",
"4 34.0 2.0 416.0 1.0 0.0 \n",
"\n",
" purchase_date_min purchase_date_max time_between_purchase \\\n",
"0 5.177187 5.177187 0.000000 \n",
"1 426.265613 426.265613 0.000000 \n",
"2 436.033437 436.033437 0.000000 \n",
"3 5.196412 5.196412 0.000000 \n",
"4 478.693148 115.631470 363.061678 \n",
"\n",
" nb_tickets_internet fidelity ... gender_female gender_male \\\n",
"0 0.0 1 ... 1 0 \n",
"1 0.0 2 ... 0 1 \n",
"2 0.0 2 ... 1 0 \n",
"3 0.0 1 ... 1 0 \n",
"4 0.0 4 ... 1 0 \n",
"\n",
" gender_other nb_campaigns nb_campaigns_opened has_purchased \\\n",
"0 0 0.0 0.0 0.0 \n",
"1 0 0.0 0.0 1.0 \n",
"2 0 0.0 0.0 0.0 \n",
"3 0 0.0 0.0 0.0 \n",
"4 0 0.0 0.0 1.0 \n",
"\n",
" has_purchased_estim score quartile score_adjusted \n",
"0 1.0 0.657671 3 0.240397 \n",
"1 0.0 0.266538 2 0.056482 \n",
"2 0.0 0.214668 1 0.043089 \n",
"3 1.0 0.657770 3 0.240478 \n",
"4 1.0 0.894173 4 0.581920 \n",
"\n",
"[5 rows x 22 columns]"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X_test_segment.head()"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "29633dd2-8b4b-48dc-be02-52f4015e686d",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>score</th>\n",
" <th>score_adjusted</th>\n",
" <th>has_purchased</th>\n",
" </tr>\n",
" <tr>\n",
" <th>quartile</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0.132457</td>\n",
" <td>0.025105</td>\n",
" <td>0.015691</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0.338914</td>\n",
" <td>0.079990</td>\n",
" <td>0.098486</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0.630647</td>\n",
" <td>0.225757</td>\n",
" <td>0.214729</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0.905216</td>\n",
" <td>0.661997</td>\n",
" <td>0.650133</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" score score_adjusted has_purchased\n",
"quartile \n",
"1 0.132457 0.025105 0.015691\n",
"2 0.338914 0.079990 0.098486\n",
"3 0.630647 0.225757 0.214729\n",
"4 0.905216 0.661997 0.650133"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X_test_segment.groupby(\"quartile\")[[\"score\",\"score_adjusted\", \"has_purchased\"]].mean()"
]
},
{
"cell_type": "code",
"execution_count": 57,
"id": "a974589f-7952-4db2-bebf-7b69c6b09372",
"metadata": {},
"outputs": [],
"source": [
"def project_tickets_CA (df, nb_tickets, total_amount, score_adjusted, duration_ref, duration_projection) :\n",
" \n",
" duration_ratio = duration_ref/duration_projection\n",
"\n",
" df_output = df\n",
"\n",
" df_output[\"nb_tickets_projected\"] = df_output[nb_tickets] / duration_ratio\n",
" df_output[\"total_amount_projected\"] = df_output[total_amount] / duration_ratio\n",
" \n",
" df_output[\"nb_tickets_expected\"] = df_output[score_adjusted] * df_output[\"nb_tickets_projected\"]\n",
" df_output[\"total_amount_expected\"] = df_output[score_adjusted] * df_output[\"total_amount_projected\"]\n",
"\n",
" return df_output\n"
]
},
{
"cell_type": "code",
"execution_count": 124,
"id": "1e000901-717d-4851-9db2-df90998d35ed",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>nb_tickets</th>\n",
" <th>nb_purchases</th>\n",
" <th>total_amount</th>\n",
" <th>nb_suppliers</th>\n",
" <th>vente_internet_max</th>\n",
" <th>purchase_date_min</th>\n",
" <th>purchase_date_max</th>\n",
" <th>time_between_purchase</th>\n",
" <th>nb_tickets_internet</th>\n",
" <th>fidelity</th>\n",
" <th>...</th>\n",
" <th>gender_female</th>\n",
" <th>gender_male</th>\n",
" <th>gender_other</th>\n",
" <th>nb_campaigns</th>\n",
" <th>nb_campaigns_opened</th>\n",
" <th>has_purchased</th>\n",
" <th>has_purchased_estim</th>\n",
" <th>score</th>\n",
" <th>quartile</th>\n",
" <th>score_adjusted</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>4.0</td>\n",
" <td>1.0</td>\n",
" <td>100.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>5.177187</td>\n",
" <td>5.177187</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.657671</td>\n",
" <td>3</td>\n",
" <td>0.240397</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>55.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>426.265613</td>\n",
" <td>426.265613</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>2</td>\n",
" <td>...</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>0.266538</td>\n",
" <td>2</td>\n",
" <td>0.056482</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>17.0</td>\n",
" <td>1.0</td>\n",
" <td>80.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>436.033437</td>\n",
" <td>436.033437</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>2</td>\n",
" <td>...</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.214668</td>\n",
" <td>1</td>\n",
" <td>0.043089</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>4.0</td>\n",
" <td>1.0</td>\n",
" <td>120.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>5.196412</td>\n",
" <td>5.196412</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.657770</td>\n",
" <td>3</td>\n",
" <td>0.240478</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>34.0</td>\n",
" <td>2.0</td>\n",
" <td>416.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>478.693148</td>\n",
" <td>115.631470</td>\n",
" <td>363.061678</td>\n",
" <td>0.0</td>\n",
" <td>4</td>\n",
" <td>...</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>0.894173</td>\n",
" <td>4</td>\n",
" <td>0.581920</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96091</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>67.31</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>278.442257</td>\n",
" <td>278.442257</td>\n",
" <td>0.000000</td>\n",
" <td>1.0</td>\n",
" <td>2</td>\n",
" <td>...</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>15.0</td>\n",
" <td>5.0</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>0.623551</td>\n",
" <td>3</td>\n",
" <td>0.214369</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96092</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>61.41</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>189.207373</td>\n",
" <td>189.207373</td>\n",
" <td>0.000000</td>\n",
" <td>1.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>12.0</td>\n",
" <td>9.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.682521</td>\n",
" <td>3</td>\n",
" <td>0.261526</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96093</th>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>550.000000</td>\n",
" <td>550.000000</td>\n",
" <td>-1.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>29.0</td>\n",
" <td>3.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.117192</td>\n",
" <td>1</td>\n",
" <td>0.021400</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96094</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>79.43</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>279.312905</td>\n",
" <td>279.312905</td>\n",
" <td>0.000000</td>\n",
" <td>1.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>20.0</td>\n",
" <td>4.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.625185</td>\n",
" <td>3</td>\n",
" <td>0.215545</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96095</th>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>550.000000</td>\n",
" <td>550.000000</td>\n",
" <td>-1.000000</td>\n",
" <td>0.0</td>\n",
" <td>2</td>\n",
" <td>...</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>31.0</td>\n",
" <td>4.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.319585</td>\n",
" <td>2</td>\n",
" <td>0.071817</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>96096 rows × 22 columns</p>\n",
"</div>"
],
"text/plain": [
" nb_tickets nb_purchases total_amount nb_suppliers \\\n",
"0 4.0 1.0 100.00 1.0 \n",
"1 1.0 1.0 55.00 1.0 \n",
"2 17.0 1.0 80.00 1.0 \n",
"3 4.0 1.0 120.00 1.0 \n",
"4 34.0 2.0 416.00 1.0 \n",
"... ... ... ... ... \n",
"96091 1.0 1.0 67.31 1.0 \n",
"96092 1.0 1.0 61.41 1.0 \n",
"96093 0.0 0.0 0.00 0.0 \n",
"96094 1.0 1.0 79.43 1.0 \n",
"96095 0.0 0.0 0.00 0.0 \n",
"\n",
" vente_internet_max purchase_date_min purchase_date_max \\\n",
"0 0.0 5.177187 5.177187 \n",
"1 0.0 426.265613 426.265613 \n",
"2 0.0 436.033437 436.033437 \n",
"3 0.0 5.196412 5.196412 \n",
"4 0.0 478.693148 115.631470 \n",
"... ... ... ... \n",
"96091 1.0 278.442257 278.442257 \n",
"96092 1.0 189.207373 189.207373 \n",
"96093 0.0 550.000000 550.000000 \n",
"96094 1.0 279.312905 279.312905 \n",
"96095 0.0 550.000000 550.000000 \n",
"\n",
" time_between_purchase nb_tickets_internet fidelity ... \\\n",
"0 0.000000 0.0 1 ... \n",
"1 0.000000 0.0 2 ... \n",
"2 0.000000 0.0 2 ... \n",
"3 0.000000 0.0 1 ... \n",
"4 363.061678 0.0 4 ... \n",
"... ... ... ... ... \n",
"96091 0.000000 1.0 2 ... \n",
"96092 0.000000 1.0 1 ... \n",
"96093 -1.000000 0.0 1 ... \n",
"96094 0.000000 1.0 1 ... \n",
"96095 -1.000000 0.0 2 ... \n",
"\n",
" gender_female gender_male gender_other nb_campaigns \\\n",
"0 1 0 0 0.0 \n",
"1 0 1 0 0.0 \n",
"2 1 0 0 0.0 \n",
"3 1 0 0 0.0 \n",
"4 1 0 0 0.0 \n",
"... ... ... ... ... \n",
"96091 0 1 0 15.0 \n",
"96092 0 1 0 12.0 \n",
"96093 1 0 0 29.0 \n",
"96094 0 1 0 20.0 \n",
"96095 0 1 0 31.0 \n",
"\n",
" nb_campaigns_opened has_purchased has_purchased_estim score \\\n",
"0 0.0 0.0 1.0 0.657671 \n",
"1 0.0 1.0 0.0 0.266538 \n",
"2 0.0 0.0 0.0 0.214668 \n",
"3 0.0 0.0 1.0 0.657770 \n",
"4 0.0 1.0 1.0 0.894173 \n",
"... ... ... ... ... \n",
"96091 5.0 1.0 1.0 0.623551 \n",
"96092 9.0 0.0 1.0 0.682521 \n",
"96093 3.0 0.0 0.0 0.117192 \n",
"96094 4.0 0.0 1.0 0.625185 \n",
"96095 4.0 0.0 0.0 0.319585 \n",
"\n",
" quartile score_adjusted \n",
"0 3 0.240397 \n",
"1 2 0.056482 \n",
"2 1 0.043089 \n",
"3 3 0.240478 \n",
"4 4 0.581920 \n",
"... ... ... \n",
"96091 3 0.214369 \n",
"96092 3 0.261526 \n",
"96093 1 0.021400 \n",
"96094 3 0.215545 \n",
"96095 2 0.071817 \n",
"\n",
"[96096 rows x 22 columns]"
]
},
"execution_count": 124,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X_test_segment"
]
},
{
"cell_type": "code",
"execution_count": 56,
"id": "dd8a52e1-d06e-4790-8687-8e58e3e6b84e",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_519/3509011500.py:7: SettingWithCopyWarning: \n",
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
"Try using .loc[row_indexer,col_indexer] = value instead\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
" df_output[\"nb_tickets_projected\"] = df_output[nb_tickets] / duration_ratio\n",
"/tmp/ipykernel_519/3509011500.py:8: SettingWithCopyWarning: \n",
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
"Try using .loc[row_indexer,col_indexer] = value instead\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
" df_output[\"total_amount_projected\"] = df_output[total_amount] / duration_ratio\n",
"/tmp/ipykernel_519/3509011500.py:10: SettingWithCopyWarning: \n",
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
"Try using .loc[row_indexer,col_indexer] = value instead\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
" df_output[\"nb_tickets_expected\"] = df_output[score_adjusted] * df_output[\"nb_tickets_projected\"]\n",
"/tmp/ipykernel_519/3509011500.py:11: SettingWithCopyWarning: \n",
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
"Try using .loc[row_indexer,col_indexer] = value instead\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
" df_output[\"total_amount_expected\"] = df_output[score_adjusted] * df_output[\"total_amount_projected\"]\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>nb_tickets</th>\n",
" <th>nb_purchases</th>\n",
" <th>total_amount</th>\n",
" <th>nb_suppliers</th>\n",
" <th>vente_internet_max</th>\n",
" <th>purchase_date_min</th>\n",
" <th>purchase_date_max</th>\n",
" <th>time_between_purchase</th>\n",
" <th>nb_tickets_internet</th>\n",
" <th>fidelity</th>\n",
" <th>...</th>\n",
" <th>nb_campaigns_opened</th>\n",
" <th>has_purchased</th>\n",
" <th>has_purchased_estim</th>\n",
" <th>score</th>\n",
" <th>quartile</th>\n",
" <th>score_adjusted</th>\n",
" <th>nb_tickets_projected</th>\n",
" <th>total_amount_projected</th>\n",
" <th>nb_tickets_expected</th>\n",
" <th>total_amount_expected</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>4.0</td>\n",
" <td>1.0</td>\n",
" <td>100.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>5.177187</td>\n",
" <td>5.177187</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.657671</td>\n",
" <td>3</td>\n",
" <td>0.240397</td>\n",
" <td>2.666667</td>\n",
" <td>66.666667</td>\n",
" <td>0.641059</td>\n",
" <td>16.026472</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>55.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>426.265613</td>\n",
" <td>426.265613</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>2</td>\n",
" <td>...</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>0.266538</td>\n",
" <td>2</td>\n",
" <td>0.056482</td>\n",
" <td>0.666667</td>\n",
" <td>36.666667</td>\n",
" <td>0.037655</td>\n",
" <td>2.071006</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>17.0</td>\n",
" <td>1.0</td>\n",
" <td>80.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>436.033437</td>\n",
" <td>436.033437</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>2</td>\n",
" <td>...</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.214668</td>\n",
" <td>1</td>\n",
" <td>0.043089</td>\n",
" <td>11.333333</td>\n",
" <td>53.333333</td>\n",
" <td>0.488340</td>\n",
" <td>2.298068</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>4.0</td>\n",
" <td>1.0</td>\n",
" <td>120.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>5.196412</td>\n",
" <td>5.196412</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.657770</td>\n",
" <td>3</td>\n",
" <td>0.240478</td>\n",
" <td>2.666667</td>\n",
" <td>80.000000</td>\n",
" <td>0.641273</td>\n",
" <td>19.238202</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>34.0</td>\n",
" <td>2.0</td>\n",
" <td>416.00</td>\n",
" <td>1.0</td>\n",
" <td>0.0</td>\n",
" <td>478.693148</td>\n",
" <td>115.631470</td>\n",
" <td>363.061678</td>\n",
" <td>0.0</td>\n",
" <td>4</td>\n",
" <td>...</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>0.894173</td>\n",
" <td>4</td>\n",
" <td>0.581920</td>\n",
" <td>22.666667</td>\n",
" <td>277.333333</td>\n",
" <td>13.190183</td>\n",
" <td>161.385771</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96091</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>67.31</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>278.442257</td>\n",
" <td>278.442257</td>\n",
" <td>0.000000</td>\n",
" <td>1.0</td>\n",
" <td>2</td>\n",
" <td>...</td>\n",
" <td>5.0</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>0.623551</td>\n",
" <td>3</td>\n",
" <td>0.214369</td>\n",
" <td>0.666667</td>\n",
" <td>44.873333</td>\n",
" <td>0.142913</td>\n",
" <td>9.619467</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96092</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>61.41</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>189.207373</td>\n",
" <td>189.207373</td>\n",
" <td>0.000000</td>\n",
" <td>1.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>9.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.682521</td>\n",
" <td>3</td>\n",
" <td>0.261526</td>\n",
" <td>0.666667</td>\n",
" <td>40.940000</td>\n",
" <td>0.174351</td>\n",
" <td>10.706885</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96093</th>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>550.000000</td>\n",
" <td>550.000000</td>\n",
" <td>-1.000000</td>\n",
" <td>0.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>3.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.117192</td>\n",
" <td>1</td>\n",
" <td>0.021400</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96094</th>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>79.43</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>279.312905</td>\n",
" <td>279.312905</td>\n",
" <td>0.000000</td>\n",
" <td>1.0</td>\n",
" <td>1</td>\n",
" <td>...</td>\n",
" <td>4.0</td>\n",
" <td>0.0</td>\n",
" <td>1.0</td>\n",
" <td>0.625185</td>\n",
" <td>3</td>\n",
" <td>0.215545</td>\n",
" <td>0.666667</td>\n",
" <td>52.953333</td>\n",
" <td>0.143697</td>\n",
" <td>11.413840</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96095</th>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>550.000000</td>\n",
" <td>550.000000</td>\n",
" <td>-1.000000</td>\n",
" <td>0.0</td>\n",
" <td>2</td>\n",
" <td>...</td>\n",
" <td>4.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.319585</td>\n",
" <td>2</td>\n",
" <td>0.071817</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>96096 rows × 26 columns</p>\n",
"</div>"
],
"text/plain": [
" nb_tickets nb_purchases total_amount nb_suppliers \\\n",
"0 4.0 1.0 100.00 1.0 \n",
"1 1.0 1.0 55.00 1.0 \n",
"2 17.0 1.0 80.00 1.0 \n",
"3 4.0 1.0 120.00 1.0 \n",
"4 34.0 2.0 416.00 1.0 \n",
"... ... ... ... ... \n",
"96091 1.0 1.0 67.31 1.0 \n",
"96092 1.0 1.0 61.41 1.0 \n",
"96093 0.0 0.0 0.00 0.0 \n",
"96094 1.0 1.0 79.43 1.0 \n",
"96095 0.0 0.0 0.00 0.0 \n",
"\n",
" vente_internet_max purchase_date_min purchase_date_max \\\n",
"0 0.0 5.177187 5.177187 \n",
"1 0.0 426.265613 426.265613 \n",
"2 0.0 436.033437 436.033437 \n",
"3 0.0 5.196412 5.196412 \n",
"4 0.0 478.693148 115.631470 \n",
"... ... ... ... \n",
"96091 1.0 278.442257 278.442257 \n",
"96092 1.0 189.207373 189.207373 \n",
"96093 0.0 550.000000 550.000000 \n",
"96094 1.0 279.312905 279.312905 \n",
"96095 0.0 550.000000 550.000000 \n",
"\n",
" time_between_purchase nb_tickets_internet fidelity ... \\\n",
"0 0.000000 0.0 1 ... \n",
"1 0.000000 0.0 2 ... \n",
"2 0.000000 0.0 2 ... \n",
"3 0.000000 0.0 1 ... \n",
"4 363.061678 0.0 4 ... \n",
"... ... ... ... ... \n",
"96091 0.000000 1.0 2 ... \n",
"96092 0.000000 1.0 1 ... \n",
"96093 -1.000000 0.0 1 ... \n",
"96094 0.000000 1.0 1 ... \n",
"96095 -1.000000 0.0 2 ... \n",
"\n",
" nb_campaigns_opened has_purchased has_purchased_estim score \\\n",
"0 0.0 0.0 1.0 0.657671 \n",
"1 0.0 1.0 0.0 0.266538 \n",
"2 0.0 0.0 0.0 0.214668 \n",
"3 0.0 0.0 1.0 0.657770 \n",
"4 0.0 1.0 1.0 0.894173 \n",
"... ... ... ... ... \n",
"96091 5.0 1.0 1.0 0.623551 \n",
"96092 9.0 0.0 1.0 0.682521 \n",
"96093 3.0 0.0 0.0 0.117192 \n",
"96094 4.0 0.0 1.0 0.625185 \n",
"96095 4.0 0.0 0.0 0.319585 \n",
"\n",
" quartile score_adjusted nb_tickets_projected total_amount_projected \\\n",
"0 3 0.240397 2.666667 66.666667 \n",
"1 2 0.056482 0.666667 36.666667 \n",
"2 1 0.043089 11.333333 53.333333 \n",
"3 3 0.240478 2.666667 80.000000 \n",
"4 4 0.581920 22.666667 277.333333 \n",
"... ... ... ... ... \n",
"96091 3 0.214369 0.666667 44.873333 \n",
"96092 3 0.261526 0.666667 40.940000 \n",
"96093 1 0.021400 0.000000 0.000000 \n",
"96094 3 0.215545 0.666667 52.953333 \n",
"96095 2 0.071817 0.000000 0.000000 \n",
"\n",
" nb_tickets_expected total_amount_expected \n",
"0 0.641059 16.026472 \n",
"1 0.037655 2.071006 \n",
"2 0.488340 2.298068 \n",
"3 0.641273 19.238202 \n",
"4 13.190183 161.385771 \n",
"... ... ... \n",
"96091 0.142913 9.619467 \n",
"96092 0.174351 10.706885 \n",
"96093 0.000000 0.000000 \n",
"96094 0.143697 11.413840 \n",
"96095 0.000000 0.000000 \n",
"\n",
"[96096 rows x 26 columns]"
]
},
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X_test_segment = project_tickets_CA (X_test_segment, \"nb_tickets\", \"total_amount\", \"score_adjusted\", duration_ref=1.5, duration_projection=1)\n",
"X_test_segment"
]
},
{
"cell_type": "code",
"execution_count": 169,
"id": "78d12889-b310-4eca-8a2a-8f2535c7b2e5",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>quartile</th>\n",
" <th>size</th>\n",
" <th>size_perct</th>\n",
" <th>nb_tickets_expected</th>\n",
" <th>total_amount_expected</th>\n",
" <th>perct_revenue_recovered</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>1</td>\n",
" <td>37410</td>\n",
" <td>38.929820</td>\n",
" <td>84.764915</td>\n",
" <td>1.867190e+03</td>\n",
" <td>4.384354</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2</td>\n",
" <td>29517</td>\n",
" <td>30.716159</td>\n",
" <td>2899.288091</td>\n",
" <td>7.446102e+04</td>\n",
" <td>9.854069</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>3</td>\n",
" <td>20137</td>\n",
" <td>20.955087</td>\n",
" <td>10876.786661</td>\n",
" <td>3.442867e+05</td>\n",
" <td>22.842135</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>4</td>\n",
" <td>9032</td>\n",
" <td>9.398934</td>\n",
" <td>215194.829104</td>\n",
" <td>9.899418e+06</td>\n",
" <td>90.107285</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" quartile size size_perct nb_tickets_expected total_amount_expected \\\n",
"0 1 37410 38.929820 84.764915 1.867190e+03 \n",
"1 2 29517 30.716159 2899.288091 7.446102e+04 \n",
"2 3 20137 20.955087 10876.786661 3.442867e+05 \n",
"3 4 9032 9.398934 215194.829104 9.899418e+06 \n",
"\n",
" perct_revenue_recovered \n",
"0 4.384354 \n",
"1 9.854069 \n",
"2 22.842135 \n",
"3 90.107285 "
]
},
"execution_count": 169,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# compute nb tickets estimated and total amount expected\n",
"X_test_expected_CA = X_test_segment.groupby(\"quartile\")[[\"nb_tickets_expected\", \"total_amount_expected\"]].sum().reset_index()\n",
"\n",
"# number of customers by segment\n",
"X_test_expected_CA.insert(1, \"size\", X_test_segment.groupby(\"quartile\").size().values)\n",
"\n",
"# size in percent of all customers\n",
"X_test_expected_CA.insert(2, \"size_perct\", 100 * X_test_expected_CA[\"size\"]/X_test_expected_CA[\"size\"].sum())\n",
"\n",
"# compute share of CA recovered\n",
"duration_ref=1.5\n",
"duration_projection=1\n",
"duration_ratio=duration_ref/duration_projection\n",
"\n",
"X_test_expected_CA[\"perct_revenue_recovered\"] = 100 * duration_ratio * X_test_expected_CA[\"total_amount_expected\"] / \\\n",
"X_test_segment.groupby(\"quartile\")[\"total_amount\"].sum().values\n",
"\n",
"X_test_expected_CA"
]
},
{
"cell_type": "code",
"execution_count": 31,
"id": "f58f9151-2f91-45df-abb7-1ddcf0652adc",
"metadata": {},
"outputs": [],
"source": [
"# generalization with a function\n",
"\n",
"def summary_expected_CA(df, segment, nb_tickets_expected, total_amount_expected, total_amount) :\n",
" \n",
" # compute nb tickets estimated and total amount expected\n",
" df_expected_CA = df.groupby(segment)[[nb_tickets_expected, total_amount_expected]].sum().reset_index()\n",
" \n",
" # number of customers by segment\n",
" df_expected_CA.insert(1, \"size\", df.groupby(segment).size().values)\n",
" \n",
" # size in percent of all customers\n",
" df_expected_CA.insert(2, \"size_perct\", 100 * df_expected_CA[\"size\"]/df_expected_CA[\"size\"].sum())\n",
" \n",
" # compute share of CA recovered\n",
" duration_ref=1.5\n",
" duration_projection=1\n",
" duration_ratio=duration_ref/duration_projection\n",
" \n",
" df_expected_CA[\"perct_revenue_recovered\"] = 100 * duration_ratio * df_expected_CA[total_amount_expected] / \\\n",
" df.groupby(segment)[total_amount].sum().values\n",
" \n",
" return df_expected_CA"
]
},
{
"cell_type": "code",
"execution_count": 38,
"id": "c8df6c80-43e8-4f00-9cd3-eb9022744313",
"metadata": {},
"outputs": [],
"source": [
"round(summary_expected_CA(df=X_test_segment, segment=\"quartile\", nb_tickets_expected=\"nb_tickets_expected\", \n",
" total_amount_expected=\"total_amount_expected\", total_amount=\"total_amount\"),2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d45dbf34-26f4-4340-91b9-ab6389b5466f",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "88ea1b3d-01ba-4edf-aecf-0a6747a86ca6",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "ac706ed7-defa-4df1-82e1-06f12fc1b6ad",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "26cc273c-17b5-4f46-89e9-773092d6e53a",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "9c471bdd-25c2-420a-a8a1-3add9f003cbc",
"metadata": {},
"source": [
"## Just to try, same computation with score instead of score adjusted\n",
"\n",
"seems overestimated : if only 14% of customers come back, how can we recover 22% of the revenue from the segment that is least likely to buy ?? ..."
]
},
{
"cell_type": "code",
"execution_count": 201,
"id": "53684a24-1809-465f-8e21-b9295e34582a",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_620/3599949626.py:7: SettingWithCopyWarning: \n",
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
"Try using .loc[row_indexer,col_indexer] = value instead\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
" df_output[\"nb_tickets_projected\"] = df_output[nb_tickets] / duration_ratio\n",
"/tmp/ipykernel_620/3599949626.py:8: SettingWithCopyWarning: \n",
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
"Try using .loc[row_indexer,col_indexer] = value instead\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
" df_output[\"total_amount_projected\"] = df_output[total_amount] / duration_ratio\n",
"/tmp/ipykernel_620/3599949626.py:10: SettingWithCopyWarning: \n",
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
"Try using .loc[row_indexer,col_indexer] = value instead\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
" df_output[\"nb_tickets_expected\"] = df_output[score_adjusted] * df_output[\"nb_tickets_projected\"]\n",
"/tmp/ipykernel_620/3599949626.py:11: SettingWithCopyWarning: \n",
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
"Try using .loc[row_indexer,col_indexer] = value instead\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
" df_output[\"total_amount_expected\"] = df_output[score_adjusted] * df_output[\"total_amount_projected\"]\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>quartile</th>\n",
" <th>size</th>\n",
" <th>size_perct</th>\n",
" <th>nb_tickets_expected</th>\n",
" <th>total_amount_expected</th>\n",
" <th>perct_revenue_recovered</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>1</td>\n",
" <td>37410</td>\n",
" <td>38.929820</td>\n",
" <td>419.757918</td>\n",
" <td>9.245081e+03</td>\n",
" <td>21.708404</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2</td>\n",
" <td>29517</td>\n",
" <td>30.716159</td>\n",
" <td>11549.060736</td>\n",
" <td>2.965220e+05</td>\n",
" <td>39.241320</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>3</td>\n",
" <td>20137</td>\n",
" <td>20.955087</td>\n",
" <td>29997.854731</td>\n",
" <td>9.547519e+05</td>\n",
" <td>63.344224</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>4</td>\n",
" <td>9032</td>\n",
" <td>9.398934</td>\n",
" <td>244655.821195</td>\n",
" <td>1.073601e+07</td>\n",
" <td>97.722201</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" quartile size size_perct nb_tickets_expected total_amount_expected \\\n",
"0 1 37410 38.929820 419.757918 9.245081e+03 \n",
"1 2 29517 30.716159 11549.060736 2.965220e+05 \n",
"2 3 20137 20.955087 29997.854731 9.547519e+05 \n",
"3 4 9032 9.398934 244655.821195 1.073601e+07 \n",
"\n",
" perct_revenue_recovered \n",
"0 21.708404 \n",
"1 39.241320 \n",
"2 63.344224 \n",
"3 97.722201 "
]
},
"execution_count": 201,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X_test_segment_bis = project_tickets_CA (X_test_segment, \"nb_tickets\", \"total_amount\", \"score\", duration_ref=1.5, duration_projection=1)\n",
"\n",
"# compute nb tickets estimated and total amount expected\n",
"X_test_expected_CA_bis = X_test_segment_bis.groupby(\"quartile\")[[\"nb_tickets_expected\", \"total_amount_expected\"]].sum().reset_index()\n",
"\n",
"# number of customers by segment\n",
"X_test_expected_CA_bis.insert(1, \"size\", X_test_segment_bis.groupby(\"quartile\").size().values)\n",
"\n",
"# size in percent of all customers\n",
"X_test_expected_CA_bis.insert(2, \"size_perct\", 100 * X_test_expected_CA_bis[\"size\"]/X_test_expected_CA_bis[\"size\"].sum())\n",
"\n",
"# compute share of CA recovered\n",
"duration_ref=1.5\n",
"duration_projection=1\n",
"duration_ratio=duration_ref/duration_projection\n",
"\n",
"X_test_expected_CA_bis[\"perct_revenue_recovered\"] = 100 * duration_ratio * X_test_expected_CA_bis[\"total_amount_expected\"] / \\\n",
"X_test_segment_bis.groupby(\"quartile\")[\"total_amount\"].sum().values\n",
"\n",
"X_test_expected_CA_bis"
]
},
{
"cell_type": "code",
"execution_count": 203,
"id": "7dc66d1e-da03-4513-96e4-d9a43ac0a2c8",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"overall share of revenue recovered : 90.26 %\n"
]
}
],
"source": [
"print(\"overall share of revenue recovered : \", round(100 * duration_ratio * X_test_expected_CA_bis[\"total_amount_expected\"].sum() / \\\n",
"X_test_segment_bis[\"total_amount\"].sum(),2), \"%\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "67cc9c5c-fff2-4d3c-8bfc-b59e06fa6e3a",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "aab045f6-81a1-4c02-9724-eec32b30a355",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "673f2969-7b9a-44c1-abf5-5679fca877ce",
"metadata": {},
"source": [
"## Last pieces of analysis"
]
},
{
"cell_type": "code",
"execution_count": 161,
"id": "2365bb13-0f3f-49d5-bf91-52c92abebcee",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"overall share of revenue recovered : 77.64%\n"
]
}
],
"source": [
"# global revenue recovered\n",
"global_revenue_recovered = round(100 * duration_ratio * X_test_expected_CA[\"total_amount_expected\"].sum() / \\\n",
"X_test_segment[\"total_amount\"].sum(),2)\n",
"print(f\"overall share of revenue recovered : {global_revenue_recovered}%\")"
]
},
{
"cell_type": "code",
"execution_count": 163,
"id": "16b17f35-57dd-459a-8989-129143dc0952",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0 0.018093\n",
"1 0.721519\n",
"2 3.336101\n",
"3 95.924287\n",
"Name: total_amount_expected, dtype: float64"
]
},
"execution_count": 163,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"100 * X_test_expected_CA[\"total_amount_expected\"]/X_test_expected_CA[\"total_amount_expected\"].sum()"
]
},
{
"cell_type": "code",
"execution_count": 166,
"id": "dee4a200-eefe-4377-8e80-59ad33edd3c0",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"quartile\n",
"1 0.320407\n",
"2 5.685020\n",
"3 11.339715\n",
"4 82.654858\n",
"Name: total_amount, dtype: float64"
]
},
"execution_count": 166,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# le segment 4 représente 83% du CA actuel et 96% du CA lié aux anciens clients pour l'année prochaine\n",
"100 * X_test_segment.groupby(\"quartile\")[\"total_amount\"].sum()/X_test_segment[\"total_amount\"].sum()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6a30506c-2175-4efd-b3cb-349ad3aaa3e3",
"metadata": {},
"outputs": [],
"source": [
"# graphique - loi de Pareto sur le CA généré\n"
]
},
{
"cell_type": "code",
"execution_count": 177,
"id": "c1e6f020-ef18-40b4-bfc1-19f98cb2796e",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"count 96096.000000\n",
"mean 207.475735\n",
"std 4720.046248\n",
"min -48831.800000\n",
"25% 0.000000\n",
"50% 0.000000\n",
"75% 60.000000\n",
"max 624890.000000\n",
"Name: total_amount, dtype: float64"
]
},
"execution_count": 177,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X_test_segment[\"total_amount\"].describe() # total amount négatif ???\n"
]
},
{
"cell_type": "code",
"execution_count": 184,
"id": "d301a50e-7c68-40f0-9245-a4eea64c387b",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0 -4.883180e+04\n",
"1 -6.483180e+04\n",
"2 -7.683860e+04\n",
"3 -8.683860e+04\n",
"4 -9.683860e+04\n",
" ... \n",
"96091 1.802247e+07\n",
"96092 1.839238e+07\n",
"96093 1.877219e+07\n",
"96094 1.931270e+07\n",
"96095 1.993759e+07\n",
"Name: total_amount, Length: 96096, dtype: float64"
]
},
"execution_count": 184,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.cumsum(X_test_segment[\"total_amount\"].sort_values()).reset_index()[\"total_amount\"]"
]
},
{
"cell_type": "code",
"execution_count": 200,
"id": "864d0206-7f5e-4d33-8f4b-fe685c3bd916",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAGwCAYAAABVdURTAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAABHRElEQVR4nO3de1xUdf4/8NdwmeE+yh0EQRQMNDVhvWBmWmBabuq2umveLxvdvJBarLtZVl9LV8Xylq2XdTPTTFvrRyZp3lBLELQUFQVBZJBA5SJym/n8/iDGRkBmcIbDDK/n4zGPmjPn8p7j1Hn5+XzO58iEEAJEREREFsJK6gKIiIiIjInhhoiIiCwKww0RERFZFIYbIiIisigMN0RERGRRGG6IiIjIojDcEBERkUWxkbqAlqbRaJCXlwdnZ2fIZDKpyyEiIiI9CCFQWloKX19fWFndv22mzYWbvLw8+Pv7S10GERERNcPVq1fh5+d333XaXLhxdnYGUHtyXFxcJK6GiIiI9FFSUgJ/f3/tdfx+2ly4qeuKcnFxYbghIiIyM/oMKeGAYiIiIrIoDDdERERkURhuiIiIyKIw3BAREZFFYbghIiIii8JwQ0RERBaF4YaIiIgsCsMNERERWRSGGyIiIrIoDDdERERkURhuiIiIyKIw3BAREZFFaXMPziQi/QghUFmjQWW1BhU1alSrNVKX1KimHqTX1GP29HgOH2RN7KWpfTR5iCa3b7rIB63B1OdRn+/Q5HmQ+DvqV8OD/VZMfXz99tHU9o2vIQNgZfWAX/IBSRpuDh8+jKVLlyIlJQUqlQq7d+/GyJEj77vNoUOHEBsbi7Nnz8LX1xfz589HTExMyxRMZCaq1RrcuF2FW+XVKL5zz6u8qt6yssoaVFRrUFGtRmXN3X8SERlKJgNmDgnGnKgQyWqQNNzcvn0bPXv2xJQpU/CnP/2pyfWzsrIwfPhwzJgxA59++imSkpLw0ksvwcPDQ6/ticxdjVqDottVuF5SgYKSSlwvrcD1kkoUlFTULiutxPWSShTdroQQxjuuTAbYWlvp9bfalqbX12xiJaHHXpo6n/rUIZrYiX770GMlIgkJAfwv7VrbDTfDhg3DsGHD9F5/3bp16NixI+Lj4wEAoaGhSE5Oxr/+9a9Gw01lZSUqKyu170tKSh6oZiJTEkLg17JKXL1Rjqs37iDnRjmu3ihHzo1y5N68A1XxHWj0vLhZyQClve3dl4P8t3+30V1ubwtnO1vY2VpDYWOl8087WysobKxhay1rsjmfzEeTIUuP31hTqzR1DP32oU8dD/5dmjxGWwrHD3jOf7lWgvEbfkRFtbQtv2Y15ub48eOIjo7WWTZ06FBs2LAB1dXVsLW1rbfN4sWL8fbbb7dUiUR6qahW40rRbVwuuI3MX8tw+dcyZBbeRuavt1FWWXPfba1kgIezAl4udvB0toOniwJeznbwcqldVveZq6Mc1hL3e1Pr1OS4E6P8bPjba4tcHeUAALXETYxmFW7y8/Ph5eWls8zLyws1NTUoLCyEj49PvW3i4uIQGxurfV9SUgJ/f3+T10oE1IaYi9dLcV5VivP5pb+FmDLk3rzT6N+grGSAj9Ie/q728G/vgI6uDujo5gC/9g7wb28PNycFQwsRtUr+rvb4ZGIE7GylvRnbrMINUP9vHHXNdI39TUShUEChUJi8LmrbhBBQFVfgfH4J0lWlSFeVIF1VgqzC2412I7nY2aCzpxOC3J0Q5OGIzh5O6OzhiI5uDlDYWLfsFyAiMgJnO1tEhXk1vaKJmVW48fb2Rn5+vs6ygoIC2NjYwM3NTaKqqK0RQuDarTs4k1uM01dv4UxuMc6pSlB8p7rB9V0d5Qj1cUZXLxcEezkhyN0RnT2d4OYo5zgWIiITMKtw079/f3z99dc6y/bt24eIiIgGx9sQGcON21U4nXtLG2ROX72FottV9daztpKhs4cjQn1c8JC3C0J9nBHm4wIPZwVDDBFRC5I03JSVleHSpUva91lZWUhLS4Orqys6duyIuLg4XLt2DVu2bAEAxMTEYNWqVYiNjcWMGTNw/PhxbNiwAdu2bZPqK5CFqVFrcD6/FKdybiIl+yZO5dzE1Rt36q1nYyVDV29n9PRvh55+SnTzVaKLpxPsbNmdREQkNUnDTXJyMgYPHqx9Xzfwd9KkSdi8eTNUKhVycnK0n3fq1AkJCQmYM2cOVq9eDV9fX3z44Yec44aa7VZ5FVJzbiEluzbMnM69hfIqdb31gtwd0dO/HXr4KdHTvx3CfFwYZIiIWimZ0GcyAgtSUlICpVKJ4uJiuLi4SF0OtbAbt6twIrMIxy8X4URmETIKyuqt46ywwSMB7RHesT16B7RDD792UNqz25OISEqGXL/NaswNkaFulVfhROYNnMisDTPn80vrrdPJ3RG9O7ZHeEDtK9jTSfLnohARUfMx3JBFKa+qwfHLRTh2ubZ1Jj2/pN58Ml29nNG/sxv6BbniD4GucHPiVAFERJaE4YbMmhAClwrKcOjirzh44Vf8lHUDVfc8vbqLpxP6B7mhX5Ab+ga5wp1hhojIojHckNkpq6xB0qVCHLr4Kw5d+BXXbunezeTX3h4Dgz20rTOeznYSVUpERFJguKFWTwiBjIIyHDhfgEMXfkVy9g1Uq+/2NcltrNAvyA2DQjzweFcPBLk7cl4ZIqI2jOGGWqUatQbJ2Tfx/bnrSEy/juyicp3PA90c8HhXTwwK8UC/IDfYy3lbNhER1WK4oVajolqNIxmF+PYXFX44X4Cb5XcfZyC3sUJkZzcM/i3QBLo7SlgpERG1Zgw3JKnKGjWOZhTi/51RIfHcdZRW1mg/a+dgiyEPeSI6zAsDgz3gqODPlYiImsarBbW4arUGRzMK8c0ZFfady0dpxd1A4+1ih2EPe2NoN29EBLSHjbWVhJUSEZE5YrihFnM2rxhfplzDntPXUFh298GTXi4KDH/YB8/08MEj/u05gR4RET0QhhsyqYLSCvwvNQ9fnsrVmR3Y3UmOpx/2wTM9fRHekYGGiIiMh+GGjK5GrcH+8wX4/KccHM4ohFpTe9u23NoKUWFeGN27Ax4L8YAtu5yIiMgEGG7IaPJu3cHnJ69i+8kcXC+p1C7v3bEdRvf2w4gevlA68AGURERkWgw39EDUGoHDF3/F1h+zceB8AX5rpIGboxx/jvDHmAg/BHk4SVskERG1KQw31CylFdXYkZyLzceycPXG3ccf9A9yw7i+HTG0mzfkNux2IiKilsdwQwa5eqMcm49dwfaTV1H225w0SntbPBfuh7/26YgunmylISIiaTHckF5Ssm/ik8OZ2HcuX9v11NnDEVMf7YTRj/jx8QdERNRqMNxQo4QQOH65CB8duITjmUXa5QOD3THt0U54LNiDt3ATEVGrw3BD9Qgh8MOFAqw6cAmncm4BAGytZRj9iB+mDeyEEC9naQskIiK6D4Yb0hJC4ODFX7F830X8fK0YAKCwscJf+3TE3x4Lgm87e4krJCIiahrDDQEATmQW4V/fXUBy9k0AgIPcGhP6BWDawE7wdLaTuDoiIiL9Mdy0cT/nFmPJd+dxJKMQQG1LzcT+AYgZ1BluTgqJqyMiIjIcw00bdb2kAku/u4AvT+VCCMDGSoa/9PHHK4OD4a1kSw0REZkvhps2pqJajQ1Hs7D6h0sor1IDAJ7t5YvXorqio5uDxNURERE9OIabNkIIgb2/5OPd/5eOa7dqZxTu5d8Ob44IQ++O7SWujoiIyHgYbtqAvFt38M+vfsH+8wUAAG8XO7wx7CH8sacv56khIiKLw3BjwdQagU9PZGPJ3vO4XaWGrbUMLw7qjJjHO8NBzj96IiKyTLzCWaiL10vxxpdntJPwhQe0x/ujH0YwJ+AjIiILx3BjYTQagY1JWViy9wKq1Bo4KWzw+lNd8XzfAHZBERFRm8BwY0Gul1Rg7hentXPWDHnIE++N6g4fJWcWJiKitoPhxkLsO5uP1788g5vl1bCztcI/nwnDuD4dIZOxtYaIiNoWhhszV6PWYOl3F/Dx4UwAQDdfF6z8yyPo4ukkcWVERETSYLgxY4VllXj1s1QczywCAMwY2Anzhj4EuY2VxJURERFJh+HGTP1yrRgztiRDVVwBR7k1lv65J4Y/7CN1WURERJJjuDFDB85fxyufpaK8So0gD0esnxCOLp68xZuIiAhguDE7/z2RjYX/+wUaAQwMdsfq53vDxc5W6rKIiIhaDYYbMyGEQPz3GVi5PwMA8OdwP/zf6Idha83xNURERL/HcGMGhBBY8t0FrD14GQAw58kQzHyiC2/zJiIiagDDTSsnhMB7/y8d/z6aBQD45zNhmPZoJ4mrIiIiar0Yblq5Jd9d0Aabd57thgn9A6UtiIiIqJVjuGnFNhzN0nZFvTeqO57vGyBxRURERK0fR6O2Uv9Lu4Z3vjkHAJg3tCuDDRERkZ4Yblqh1JybmPfFGQDAlAGBeOnxzhJXREREZD4YblqZX0sr8eKnp1Cl1mBoNy/88+kw3hVFRERkAIabVqRarcHLW08hv6QCXTydsGxML1hZMdgQEREZguGmFVmeeBE/XbkBZ4UNPp4QDicFx3sTEREZiuGmlfgxswjrDtXeGbX0zz3Q2cNJ4oqIiIjME8NNK1BSUY3YHachBDA2wh9PdefTvYmIiJqL4aYVWLL3PK7duoMANwe8OSJM6nKIiIjMGsONxE5fvYWtP+YAAN4f3QOOHGdDRET0QBhuJKTWCPzjq18gBDD6kQ7o39lN6pKIiIjMHsONhL5KvYafrxXD2c4GccNDpS6HiIjIIjDcSKSqRoMV318EALz0eBd4OCskroiIiMgyMNxIZPvJHOTevAMPZwUmRfK5UURERMbCcCOBarUGa3572vcrg7vAQc5BxERERMbCcCOBhJ9VUBVXwN1JjrF/8Je6HCIiIovCcNPChBDYcDQLADChXyDsbK0lroiIiMiyMNy0sNSrt3AmtxhyGyuM79dR6nKIiIgsjuThZs2aNejUqRPs7OwQHh6OI0eO3Hf9rVu3omfPnnBwcICPjw+mTJmCoqKiFqr2wX2RnAsAeOZhH7g58Q4pIiIiY5M03Gzfvh2zZ8/GggULkJqaioEDB2LYsGHIyclpcP2jR49i4sSJmDZtGs6ePYsvvvgCJ0+exPTp01u48uapqFbjmzN5AIDnIvwkroaIiMgySRpuli9fjmnTpmH69OkIDQ1FfHw8/P39sXbt2gbXP3HiBAIDAzFz5kx06tQJjz76KF544QUkJyc3eozKykqUlJTovKSy79x1lFbUoEM7e/TrxNmIiYiITEGycFNVVYWUlBRER0frLI+OjsaxY8ca3CYyMhK5ublISEiAEALXr1/Hzp078fTTTzd6nMWLF0OpVGpf/v7S3Z30v9RrAIDRvTvAykomWR1ERESWTLJwU1hYCLVaDS8vL53lXl5eyM/Pb3CbyMhIbN26FWPHjoVcLoe3tzfatWuHjz76qNHjxMXFobi4WPu6evWqUb+HvsqranDkUiEA4JkevpLUQERE1BZIPqBYJtNtwRBC1FtW59y5c5g5cybefPNNpKSkYO/evcjKykJMTEyj+1coFHBxcdF5SeHwxUJU1Wjg72qPEC8nSWogIiJqCySbGtfd3R3W1tb1WmkKCgrqtebUWbx4MQYMGIB58+YBAHr06AFHR0cMHDgQ7777Lnx8fExed3N9n34dABAV6t1oeCMiIqIHJ1nLjVwuR3h4OBITE3WWJyYmIjIyssFtysvLYWWlW7K1de0keEII0xRqBBqNwIHzBQCAJ8M8Ja6GiIjIsknaLRUbG4t///vf2LhxI9LT0zFnzhzk5ORou5ni4uIwceJE7fojRozArl27sHbtWmRmZiIpKQkzZ85Enz594OvbesexnFOV4MbtKjgpbPCHQFepyyEiIrJokj6xcezYsSgqKsKiRYugUqnQvXt3JCQkICCg9inZKpVKZ86byZMno7S0FKtWrcJrr72Gdu3aYciQIfjggw+k+gp6SfptIHHfTq6wtZZ8mBMREZFFk4nW3J9jAiUlJVAqlSguLm6xwcWTNv6EQxd/xT+fCcO0Rzu1yDGJiIgsiSHXbzYjmFhVjQY/Zd0AAER25sR9REREpsZwY2I/XyvGnWo1XB3l6OrlLHU5REREFo/hxsTSrt4CAPTu2J6zEhMREbUAhhsTO/1buOnlr5S2ECIiojaC4cbE6lpuevq3k7QOIiKitoLhxoRu3K5Czo1yAEAPv3bSFkNERNRGMNyY0OncWwCAIA9HKO1tpS2GiIiojWC4MaGz14oBAD06cLwNERFRS2G4MaEL18sAAA/5SPMkciIioraI4caELuaXAgDntyEiImpBDDcmUlWjweVfa1tuQrwZboiIiFoKw42JXCm6jRqNgJPCBr5KO6nLISIiajMYbkwk89fbAIDOHo6QyTgzMRERUUthuDGR3Ju189v4uzpIXAkREVHbwnBjIrk37wAA/Noz3BAREbUkhhsTqWu58WtvL3ElREREbQvDjYncbblhuCEiImpJDDcmUhduOOaGiIioZTHcmEB5VQ3KKmsAAF4uvA2ciIioJTHcmEBRWRUAQG5jBUe5tcTVEBERtS0MNyZw43ZtuHFzlHOOGyIiohbGcGMC2nDjJJe4EiIioraH4cYEin4LN66OCokrISIianuaFW5qamrw/fff4+OPP0Zpae2Tr/Py8lBWVmbU4sxVUVklgNpuKSIiImpZNoZukJ2djaeeego5OTmorKxEVFQUnJ2dsWTJElRUVGDdunWmqNOs3NC23DDcEBERtTSDW25mzZqFiIgI3Lx5E/b2dyeoGzVqFPbv32/U4sxVEcMNERGRZAxuuTl69CiSkpIgl+teuAMCAnDt2jWjFWbObpUz3BAREUnF4JYbjUYDtVpdb3lubi6cnZ2NUpS5K6moncDP2c7g7EhEREQPyOBwExUVhfj4eO17mUyGsrIyLFy4EMOHDzdmbWarVBtubCWuhIiIqO0xuGlhxYoVGDx4MMLCwlBRUYFx48YhIyMD7u7u2LZtmylqNDulFdUA2HJDREQkBYOvvr6+vkhLS8O2bdtw6tQpaDQaTJs2Dc8//7zOAOO2rK7lxoXhhoiIqMU16+prb2+PqVOnYurUqcaux+wJIbQPzWS3FBERUcszONxs2bLlvp9PnDix2cVYgvIqNdQaAYDdUkRERFIw+Oo7a9YsnffV1dUoLy+HXC6Hg4NDmw83dV1S1lYy2NvyieBEREQtzeC7pW7evKnzKisrw4ULF/Doo49yQDGAssq7g4n5RHAiIqKWZ5QHZwYHB+P999+v16rTFnGOGyIiImkZ7ang1tbWyMvLM9buzJZ2jhsFBxMTERFJweDmhT179ui8F0JApVJh1apVGDBggNEKM1ec44aIiEhaBl+BR44cqfNeJpPBw8MDQ4YMwbJly4xVl9kqr6x9NIWjguGGiIhICgZfgTUajSnqsBjlVbXdUvZy3ilFREQkBaONuaFad6prw58DbwMnIiKShMEtN2q1Gps3b8b+/ftRUFBQryXnwIEDRivOHN1hyw0REZGkmjWJ3+bNm/H000+je/funMvlHneqa8fcMNwQERFJw+Bw8/nnn2PHjh0YPny4Keoxe+VVv4UbdksRERFJwuAxN3K5HF26dDFFLRahruXGgS03REREkjA43Lz22mtYuXIlhBCmqMfs3WHLDRERkaQM7pY6evQofvjhB3z77bfo1q0bbG11Z+LdtWuX0YozR3fH3HCeGyIiIikYfAVu164dRo0aZYpaLALH3BAREUnL4HCzadMmU9RhMSq0LTecQoiIiEgKzboC19TU4Pvvv8fHH3+M0tJSAEBeXh7KysqMWpw5uttyw24pIiIiKRh8Bc7OzsZTTz2FnJwcVFZWIioqCs7OzliyZAkqKiqwbt06U9RpNrQDinm3FBERkSQMbrmZNWsWIiIicPPmTdjb22uXjxo1Cvv37zdqceZI2y3FMTdERESSaNbdUklJSZDL5TrLAwICcO3aNaMVZq6qamofRyG34ZgbIiIiKRh8BdZoNFCr1fWW5+bmwtnZ2ShFmbMqdW24sbXmYymIiIikYHC4iYqKQnx8vPa9TCZDWVkZFi5c2OYfySCE0IYbttwQERFJw+BuqRUrVmDw4MEICwtDRUUFxo0bh4yMDLi7u2Pbtm2mqNFs1GgE6iZullsz3BAREUnB4HDj6+uLtLQ0bNu2DadOnYJGo8G0adPw/PPP6wwwbouqf2u1AdhyQ0REJBWDr8Dl5eWwt7fH1KlTsWrVKqxZswbTp09vdrBZs2YNOnXqBDs7O4SHh+PIkSP3Xb+yshILFixAQEAAFAoFOnfujI0bNzbr2MZWN5gYAGzZckNERCQJg6/Anp6eGD9+PL777jtoNJqmN7iP7du3Y/bs2ViwYAFSU1MxcOBADBs2DDk5OY1uM2bMGOzfvx8bNmzAhQsXsG3bNjz00EMPVIex1I23kckAGysOKCYiIpKCweFmy5YtqKysxKhRo+Dr64tZs2bh5MmTzTr48uXLMW3aNEyfPh2hoaGIj4+Hv78/1q5d2+D6e/fuxaFDh5CQkIAnn3wSgYGB6NOnDyIjI5t1fGOra7mxtbaCTMZwQ0REJAWDw83o0aPxxRdf4Pr161i8eDHS09MRGRmJkJAQLFq0SO/9VFVVISUlBdHR0TrLo6OjcezYsQa32bNnDyIiIrBkyRJ06NABISEhmDt3Lu7cudPocSorK1FSUqLzMpVqde1oYgW7pIiIiCTT7Kuws7MzpkyZgn379uH06dNwdHTE22+/rff2hYWFUKvV8PLy0lnu5eWF/Pz8BrfJzMzE0aNH8csvv2D37t2Ij4/Hzp078fLLLzd6nMWLF0OpVGpf/v7+etdoKG3LDQcTExERSabZV+GKigrs2LEDI0eORO/evVFUVIS5c+cavJ97u2+EEI126Wg0GshkMmzduhV9+vTB8OHDsXz5cmzevLnR1pu4uDgUFxdrX1evXjW4Rn1pZydmyw0REZFkDL4VfN++fdi6dSu++uorWFtb47nnnsN3332HQYMGGbQfd3d3WFtb12ulKSgoqNeaU8fHxwcdOnSAUqnULgsNDYUQArm5uQgODq63jUKhgEKhMKi25uIEfkRERNIz+Co8cuRIlJeX4z//+Q+uX7+O9evXGxxsAEAulyM8PByJiYk6yxMTExsdIDxgwADk5eWhrKxMu+zixYuwsrKCn5+fwTUY290BxRxMTEREJBWDW27y8/Ph4uJilIPHxsZiwoQJiIiIQP/+/bF+/Xrk5OQgJiYGQG2X0rVr17BlyxYAwLhx4/DOO+9gypQpePvtt1FYWIh58+Zh6tSprWICwWptyw2fCE5ERCQVg8ONi4sLLl++jE2bNuHy5ctYuXIlPD09sXfvXvj7+6Nbt25672vs2LEoKirCokWLoFKp0L17dyQkJCAgIAAAoFKpdOa8cXJyQmJiIl599VVERETAzc0NY8aMwbvvvmvo1zCJu2Nu2HJDREQkFZkQdU9D0s+hQ4cwbNgwDBgwAIcPH0Z6ejqCgoKwZMkS/PTTT9i5c6epajWKkpISKJVKFBcXG60Fqs63P6vw4tZTiAhoj50vto65d4iIiCyBIddvg8fcvPHGG3j33XeRmJgIuVyuXT548GAcP37c8GotSI2mNidac3ZiIiIiyRgcbn7++WeMGjWq3nIPDw8UFRUZpShzpREMN0RERFIzONy0a9cOKpWq3vLU1FR06NDBKEWZKzVbboiIiCRncLgZN24cXn/9deTn50Mmk0Gj0SApKQlz587FxIkTTVGj2WC3FBERkfQMDjfvvfceOnbsiA4dOqCsrAxhYWF47LHHEBkZiX/84x+mqNFsaOrCDR+aSUREJBmDbgUXQiAvLw+ffPIJ3nnnHZw6dQoajQaPPPJIg7MDtzVqjrkhIiKSnMHhJjg4GGfPnkVwcDCCgoJMVZdZ4pgbIiIi6RnULWVlZYXg4OA2f1dUY+rCjRXDDRERkWQMHnOzZMkSzJs3D7/88osp6jFrdeHGhuGGiIhIMgY/fmH8+PEoLy9Hz549IZfL6z3T6caNG0YrztyoOaCYiIhIcgaHm/j4eBOUYRk4oJiIiEh6BoebSZMmmaIOi6BWM9wQERFJzeAxN9S4upYbDigmIiKSDsONEWk4oJiIiEhyDDdGVPf4BSsOKCYiIpIMw40RcUAxERGR9BhujKhuQDG7pYiIiKSj191So0eP1nuHu3btanYx5o4DiomIiKSnV8uNUqnUvlxcXLB//34kJydrP09JScH+/fuhVCpNVqg54IBiIiIi6enVcrNp0ybtv7/++usYM2YM1q1bB2trawCAWq3GSy+9BBcXF9NUaSY4oJiIiEh6Bo+52bhxI+bOnasNNgBgbW2N2NhYbNy40ajFmRsNBxQTERFJzuBwU1NTg/T09HrL09PTodFojFKUudI+W4rhhoiISDIGP35hypQpmDp1Ki5duoR+/foBAE6cOIH3338fU6ZMMXqB5qSG4YaIiEhyBoebf/3rX/D29saKFSugUqkAAD4+Ppg/fz5ee+01oxdoTjR8KjgREZHkDA43VlZWmD9/PubPn4+SkhIAaPMDiev8Ns0NbwUnIiKSULMm8aupqcH333+Pbdu2QfZbK0VeXh7KysqMWpy5Eb8NKGa0ISIiko7BLTfZ2dl46qmnkJOTg8rKSkRFRcHZ2RlLlixBRUUF1q1bZ4o6zcJvDTdgrxQREZF0DG65mTVrFiIiInDz5k3Y29trl48aNQr79+83anFmp65biumGiIhIMga33Bw9ehRJSUmQy+U6ywMCAnDt2jWjFWaO6ua5YbYhIiKSjsEtNxqNBmq1ut7y3NxcODs7G6Uoc/VbtuGYGyIiIgkZHG6ioqIQHx+vfS+TyVBWVoaFCxdi+PDhxqzN7Ii6fik23RAREUnG4G6pFStWYPDgwQgLC0NFRQXGjRuHjIwMuLu7Y9u2baao0WwI7ZgbaesgIiJqywwON76+vkhLS8Pnn3+OlJQUaDQaTJs2Dc8//7zOAOO2SKPtlmK6ISIikorB4ebw4cOIjIzElClTdB63UFNTg8OHD+Oxxx4zaoHmhQOKiYiIpGbwmJvBgwfjxo0b9ZYXFxdj8ODBRinKXLFbioiISHoGhxshhHZW4t8rKiqCo6OjUYoyV9pJ/NgtRUREJBm9u6VGjx4NoPbuqMmTJ0OhUGg/U6vVOHPmDCIjI41foRnR8F5wIiIiyekdbpRKJYDalhtnZ2edwcNyuRz9+vXDjBkzjF+hGWG2ISIikp7e4WbTpk0AgMDAQMydO7fNd0E1pK5bio9fICIiko7Bd0stXLjQFHVYBMHHLxAREUnO4HADADt37sSOHTuQk5ODqqoqnc9OnTpllMLMkeAExURERJIz+G6pDz/8EFOmTIGnpydSU1PRp08fuLm5ITMzE8OGDTNFjWaj7vELvFuKiIhIOgaHmzVr1mD9+vVYtWoV5HI55s+fj8TERMycORPFxcWmqNFssOWGiIhIegaHm5ycHO0t3/b29igtLQUATJgwgc+W0oYbphsiIiKpGBxuvL29UVRUBAAICAjAiRMnAABZWVnaAbVtVd08N4w2RERE0jE43AwZMgRff/01AGDatGmYM2cOoqKiMHbsWIwaNcroBZoT3gpOREQkPYPvllq/fj00Gg0AICYmBq6urjh69ChGjBiBmJgYoxdoVjjmhoiISHIGhxsrKytYWd1t8BkzZgzGjBlj1KLMFbuliIiIpKdXuDlz5ozeO+zRo0ezizF32gdnMt0QERFJRq9w06tXL8hksiYHDMtkMqjVaqMUZo7uzlDMdENERCQVvcJNVlaWqeuwCNqWG0mrICIiatv0CjcBAQGmrsMiaDjPDRERkeQMHlC8ZcuW+34+ceLEZhdj9n7rlrJitiEiIpKMweFm1qxZOu+rq6tRXl4OuVwOBweHNh1uOKCYiIhIegZP4nfz5k2dV1lZGS5cuIBHH32Uj1+o65biqBsiIiLJGBxuGhIcHIz333+/XqtOW6O5m26IiIhIIkYJNwBgbW2NvLw8Y+3OLNVlGz5+gYiISDoGj7nZs2ePznshBFQqFVatWoUBAwYYrTBzxFvBiYiIpGdwuBk5cqTOe5lMBg8PDwwZMgTLli0zuIA1a9Zg6dKlUKlU6NatG+Lj4zFw4MAmt0tKSsKgQYPQvXt3pKWlGXxcU7g7iZ/EhRAREbVhBoebuodmGsP27dsxe/ZsrFmzBgMGDMDHH3+MYcOG4dy5c+jYsWOj2xUXF2PixIl44okncP36daPV86A4oJiIiEh6Rhtz0xzLly/HtGnTMH36dISGhiI+Ph7+/v5Yu3btfbd74YUXMG7cOPTv37+FKtWPAOe5ISIikprBLTdCCOzcuRM//PADCgoK6rXk7Nq1S6/9VFVVISUlBW+88YbO8ujoaBw7dqzR7TZt2oTLly/j008/xbvvvtvkcSorK1FZWal9X1JSold9zSE46IaIiEhyBrfczJo1CxMmTEBWVhacnJygVCp1XvoqLCyEWq2Gl5eXznIvLy/k5+c3uE1GRgbeeOMNbN26FTY2+uWyxYsX69Tn7++vd42GupttmG6IiIikYnDLzaeffopdu3Zh+PDhRing3ucwCSEafDaTWq3GuHHj8PbbbyMkJETv/cfFxSE2Nlb7vqSkxGQBR8PHLxAREUnO4HCjVCoRFBT0wAd2d3eHtbV1vVaagoKCeq05AFBaWork5GSkpqbilVdeAVA7uFkIARsbG+zbtw9Dhgypt51CoYBCoXjgevXCB2cSERFJzuBuqbfeegtvv/027ty580AHlsvlCA8PR2Jios7yxMREREZG1lvfxcUFP//8M9LS0rSvmJgYdO3aFWlpaejbt+8D1WMMfLYUERGR9Axuufnzn/+Mbdu2wdPTE4GBgbC1tdX5/NSpU3rvKzY2FhMmTEBERAT69++P9evXIycnBzExMQBqu5SuXbuGLVu2wMrKCt27d9fZ3tPTE3Z2dvWWS0U7z43EdRAREbVlBoebyZMnIyUlBePHj4eXl9cDdcGMHTsWRUVFWLRoEVQqFbp3746EhAQEBAQAAFQqFXJycpq9/5amYbcUERGR5GRCaG9g1oujoyO+++47PProo6aqyaRKSkqgVCpRXFwMFxcXo+574JIDuHrjDna9FIneHdsbdd9ERERtmSHXb4PH3Pj7+xs9FFgKPhSciIhIegaHm2XLlmH+/Pm4cuWKCcoxb3wqOBERkfQMHnMzfvx4lJeXo3PnznBwcKg3oPjGjRtGK87c8MGZRERE0jM43MTHx5ugDMvAGYqJiIikZ3C4mTRpkinqsAjaMTfMNkRERJIxONw0dWt2x44dm12MudOwW4qIiEhyBoebwMDA+87jolarH6ggc8ZuKSIiIukZHG5SU1N13ldXVyM1NRXLly/He++9Z7TCzBG7pYiIiKRncLjp2bNnvWURERHw9fXF0qVLMXr0aKMUZp7YLUVERCQ1g+e5aUxISAhOnjxprN2ZJQ3nuSEiIpKcwS03JSUlOu+FEFCpVHjrrbcQHBxstMLMER+cSUREJD2Dw027du3qDSgWQsDf3x+ff/650QozR9oBxUw3REREkjE43Bw4cEAn3FhZWcHDwwNdunSBjY3Bu7Modx9BynRDREQkFYPTyOOPP26CMixDXbeUFbMNERGRZAweULx48WJs3Lix3vKNGzfigw8+MEpRRERERM1lcLj5+OOP8dBDD9Vb3q1bN6xbt84oRZkr0fQqREREZGIGh5v8/Hz4+PjUW+7h4QGVSmWUoszd/WZwJiIiItMyONz4+/sjKSmp3vKkpCT4+voapSgiIiKi5jJ4QPH06dMxe/ZsVFdXY8iQIQCA/fv3Y/78+XjttdeMXqBZYb8UERGR5AwON/Pnz8eNGzfw0ksvoaqqCgBgZ2eH119/HXFxcUYv0ByxU4qIiEg6BocbmUyGDz74AP/85z+Rnp4Oe3t7BAcHQ6FQmKI+s8KGGyIiIuk1e9Y9Jycn/OEPfzBmLRaD44mJiIikY7QHZxIRERG1Bgw3RiQEO6aIiIikxnBjAjIOKSYiIpIMw40Rsd2GiIhIegw3JsABxURERNJhuCEiIiKLwnBjRBxPTEREJD2GGyIiIrIoDDdGJDikmIiISHIMNybAAcVERETSYbghIiIii8JwY0QcUExERCQ9hhsTkLFfioiISDIMN0RERGRRGG6MiL1SRERE0mO4MQF2ShEREUmH4caY2HRDREQkOYYbE+B4YiIiIukw3BAREZFFYbgxIj5+gYiISHoMNyYg45BiIiIiyTDcGBFnKCYiIpIew40JcEAxERGRdBhuiIiIyKIw3BgRe6WIiIikx3BjAuyVIiIikg7DjREJjigmIiKSHMONKbDphoiISDIMN0RERGRRGG6MiJ1SRERE0mO4MQHOUExERCQdhhsiIiKyKAw3RsSbpYiIiKTHcGMCfPwCERGRdBhuiIiIyKIw3JgAG26IiIikI3m4WbNmDTp16gQ7OzuEh4fjyJEjja67a9cuREVFwcPDAy4uLujfvz++++67FqyWiIiIWjtJw8327dsxe/ZsLFiwAKmpqRg4cCCGDRuGnJycBtc/fPgwoqKikJCQgJSUFAwePBgjRoxAampqC1deHx+9QERE1DrIhIRX5b59+6J3795Yu3atdlloaChGjhyJxYsX67WPbt26YezYsXjzzTf1Wr+kpARKpRLFxcVwcXFpVt0NEUKgU1wCAODUP6Pg6ig32r6JiIjaOkOu35K13FRVVSElJQXR0dE6y6Ojo3Hs2DG99qHRaFBaWgpXV9dG16msrERJSYnOyxTYcENERNQ6SBZuCgsLoVar4eXlpbPcy8sL+fn5eu1j2bJluH37NsaMGdPoOosXL4ZSqdS+/P39H6hufXBAMRERkXQkH1Asu2dSGCFEvWUN2bZtG9566y1s374dnp6eja4XFxeH4uJi7evq1asPXDMRERG1XjZSHdjd3R3W1tb1WmkKCgrqtebca/v27Zg2bRq++OILPPnkk/ddV6FQQKFQPHC9TWGvFBERUesgWcuNXC5HeHg4EhMTdZYnJiYiMjKy0e22bduGyZMn47PPPsPTTz9t6jKbhTMUExERSUeylhsAiI2NxYQJExAREYH+/ftj/fr1yMnJQUxMDIDaLqVr165hy5YtAGqDzcSJE7Fy5Ur069dP2+pjb28PpVIp2fcAeCs4ERFRayFpuBk7diyKioqwaNEiqFQqdO/eHQkJCQgICAAAqFQqnTlvPv74Y9TU1ODll1/Gyy+/rF0+adIkbN68uaXLb5SMQ4qJiIgkI+k8N1Iw1Tw3NWoNuiz4FgBw+s1oKB1sjbZvIiKits4s5rmxNG0qIRIREbViDDemwF4pIiIiyTDcEBERkUVhuDGStjVyiYiIqPViuDEBznNDREQkHYYbIxEcUkxERNQqMNyYABtuiIiIpMNwQ0RERBaF4cZIOKCYiIiodWC4MQEZRxQTERFJhuGGiIiILArDjQmw3YaIiEg6DDdERERkURhujIQDiomIiFoHhhsT4HhiIiIi6TDcGAlnKCYiImodGG5MQMYhxURERJJhuCEiIiKLwnBjJBxQTERE1Dow3JgABxQTERFJh+GGiIiILArDjZGwV4qIiKh1YLghIiIii8JwYySCI4qJiIhaBYYbE+CAYiIiIukw3BAREZFFYbgxEnZKERERtQ4MNybAxy8QERFJh+HGSDiemIiIqHVguDEBDigmIiKSDsMNERERWRSGG2NhtxQREVGrwHBjAuyVIiIikg7DjZEINt0QERG1Cgw3JiDjiGIiIiLJMNwQERGRRWG4MRLOc0NERNQ6MNyYADuliIiIpMNwQ0RERBaF4cZI2CtFRETUOjDcmABvliIiIpIOw42RCI4oJiIiahUYbkyA89wQERFJh+GGiIiILArDjZGwU4qIiKh1YLghIiIii8JwYyQcT0xERNQ6MNwYGccSExERSYvhhoiIiCwKw42RCA4pJiIiahUYboyMvVJERETSspG6AEtiZ2sFKw66ISIikhTDjZF4Otvh/DvDpC6DiIiozWO3FBEREVkUhhsiIiKyKAw3REREZFEYboiIiMiiMNwQERGRRZE83KxZswadOnWCnZ0dwsPDceTIkfuuf+jQIYSHh8POzg5BQUFYt25dC1VKRERE5kDScLN9+3bMnj0bCxYsQGpqKgYOHIhhw4YhJyenwfWzsrIwfPhwDBw4EKmpqfj73/+OmTNn4ssvv2zhyomIiKi1kgkh3fOs+/bti969e2Pt2rXaZaGhoRg5ciQWL15cb/3XX38de/bsQXp6unZZTEwMTp8+jePHj+t1zJKSEiiVShQXF8PFxeXBvwQRERGZnCHXb8labqqqqpCSkoLo6Gid5dHR0Th27FiD2xw/frze+kOHDkVycjKqq6sb3KayshIlJSU6LyIiIrJckoWbwsJCqNVqeHl56Sz38vJCfn5+g9vk5+c3uH5NTQ0KCwsb3Gbx4sVQKpXal7+/v3G+ABEREbVKkg8olt3zLCYhRL1lTa3f0PI6cXFxKC4u1r6uXr36gBUTERFRaybZs6Xc3d1hbW1dr5WmoKCgXutMHW9v7wbXt7GxgZubW4PbKBQKKBQK4xRNRERErZ5kLTdyuRzh4eFITEzUWZ6YmIjIyMgGt+nfv3+99fft24eIiAjY2tqarFYiIiIyH5J2S8XGxuLf//43Nm7ciPT0dMyZMwc5OTmIiYkBUNulNHHiRO36MTExyM7ORmxsLNLT07Fx40Zs2LABc+fOleorEBERUSsjWbcUAIwdOxZFRUVYtGgRVCoVunfvjoSEBAQEBAAAVCqVzpw3nTp1QkJCAubMmYPVq1fD19cXH374If70pz/pfcy6MTq8a4qIiMh81F239ZnBRtJ5bqSQm5vLO6aIiIjM1NWrV+Hn53ffddpcuNFoNMjLy4Ozs/N978pqjpKSEvj7++Pq1aucINCEeJ5bBs9zy+B5bjk81y3DVOdZCIHS0lL4+vrCyur+o2ok7ZaSgpWVVZOJ70G5uLjwP5wWwPPcMnieWwbPc8vhuW4ZpjjPSqVSr/Ukn+eGiIiIyJgYboiIiMiiMNwYkUKhwMKFCzlpoInxPLcMnueWwfPccniuW0ZrOM9tbkAxERERWTa23BAREZFFYbghIiIii8JwQ0RERBaF4YaIiIgsCsONgdasWYNOnTrBzs4O4eHhOHLkyH3XP3ToEMLDw2FnZ4egoCCsW7euhSo1b4ac5127diEqKgoeHh5wcXFB//798d1337VgtebL0N9znaSkJNjY2KBXr16mLdBCGHqeKysrsWDBAgQEBEChUKBz587YuHFjC1Vrvgw9z1u3bkXPnj3h4OAAHx8fTJkyBUVFRS1UrXk6fPgwRowYAV9fX8hkMnz11VdNbiPJdVCQ3j7//HNha2srPvnkE3Hu3Dkxa9Ys4ejoKLKzsxtcPzMzUzg4OIhZs2aJc+fOiU8++UTY2tqKnTt3tnDl5sXQ8zxr1izxwQcfiJ9++klcvHhRxMXFCVtbW3Hq1KkWrty8GHqe69y6dUsEBQWJ6Oho0bNnz5Yp1ow15zz/8Y9/FH379hWJiYkiKytL/PjjjyIpKakFqzY/hp7nI0eOCCsrK7Fy5UqRmZkpjhw5Irp16yZGjhzZwpWbl4SEBLFgwQLx5ZdfCgBi9+7d911fqusgw40B+vTpI2JiYnSWPfTQQ+KNN95ocP358+eLhx56SGfZCy+8IPr162eyGi2Boee5IWFhYeLtt982dmkWpbnneezYseIf//iHWLhwIcONHgw9z99++61QKpWiqKioJcqzGIae56VLl4qgoCCdZR9++KHw8/MzWY2WRp9wI9V1kN1SeqqqqkJKSgqio6N1lkdHR+PYsWMNbnP8+PF66w8dOhTJycmorq42Wa3mrDnn+V4ajQalpaVwdXU1RYkWobnnedOmTbh8+TIWLlxo6hItQnPO8549exAREYElS5agQ4cOCAkJwdy5c3Hnzp2WKNksNec8R0ZGIjc3FwkJCRBC4Pr169i5cyeefvrplii5zZDqOtjmHpzZXIWFhVCr1fDy8tJZ7uXlhfz8/Aa3yc/Pb3D9mpoaFBYWwsfHx2T1mqvmnOd7LVu2DLdv38aYMWNMUaJFaM55zsjIwBtvvIEjR47Axob/69BHc85zZmYmjh49Cjs7O+zevRuFhYV46aWXcOPGDY67aURzznNkZCS2bt2KsWPHoqKiAjU1NfjjH/+Ijz76qCVKbjOkug6y5cZAMplM570Qot6yptZvaDnpMvQ819m2bRveeustbN++HZ6enqYqz2Loe57VajXGjRuHt99+GyEhIS1VnsUw5Pes0Wggk8mwdetW9OnTB8OHD8fy5cuxefNmtt40wZDzfO7cOcycORNvvvkmUlJSsHfvXmRlZSEmJqYlSm1TpLgO8q9fenJ3d4e1tXW9vwUUFBTUS6V1vL29G1zfxsYGbm5uJqvVnDXnPNfZvn07pk2bhi+++AJPPvmkKcs0e4ae59LSUiQnJyM1NRWvvPIKgNqLsBACNjY22LdvH4YMGdIitZuT5vyefXx80KFDByiVSu2y0NBQCCGQm5uL4OBgk9ZsjppznhcvXowBAwZg3rx5AIAePXrA0dERAwcOxLvvvsuWdSOR6jrIlhs9yeVyhIeHIzExUWd5YmIiIiMjG9ymf//+9dbft28fIiIiYGtra7JazVlzzjNQ22IzefJkfPbZZ+wz14Oh59nFxQU///wz0tLStK+YmBh07doVaWlp6Nu3b0uVblaa83seMGAA8vLyUFZWpl128eJFWFlZwc/Pz6T1mqvmnOfy8nJYWeleAq2trQHcbVmgByfZddCkw5UtTN2thhs2bBDnzp0Ts2fPFo6OjuLKlStCCCHeeOMNMWHCBO36dbfAzZkzR5w7d05s2LCBt4LrwdDz/NlnnwkbGxuxevVqoVKptK9bt25J9RXMgqHn+V68W0o/hp7n0tJS4efnJ5577jlx9uxZcejQIREcHCymT58u1VcwC4ae502bNgkbGxuxZs0acfnyZXH06FEREREh+vTpI9VXMAulpaUiNTVVpKamCgBi+fLlIjU1VXvLfWu5DjLcGGj16tUiICBAyOVy0bt3b3Ho0CHtZ5MmTRKDBg3SWf/gwYPikUceEXK5XAQGBoq1a9e2cMXmyZDzPGjQIAGg3mvSpEktX7iZMfT3/HsMN/oz9Dynp6eLJ598Utjb2ws/Pz8RGxsrysvLW7hq82Poef7www9FWFiYsLe3Fz4+PuL5558Xubm5LVy1efnhhx/u+//b1nIdlAnB9jciIiKyHBxzQ0RERBaF4YaIiIgsCsMNERERWRSGGyIiIrIoDDdERERkURhuiIiIyKIw3BAREZFFYbghIiIii8JwQ/Q7Qgj87W9/g6urK2QyGdLS0lr0+AcPHoRMJsOtW7da9LgNSUpKwsMPPwxbW1uMHDlS6nLICK5cudLk71rq32BgYCDi4+MlOTZZDoYbot/Zu3cvNm/ejG+++QYqlQrdu3c32bEef/xxzJ49W2dZZGQkVCqVzhOhpRIbG4tevXohKysLmzdvbvHjb968Ge3atWvx41oyf39/k/+uiVoDhhui37l8+TJ8fHwQGRkJb29v2NjY1FunqqrKZMeXy+Xw9vaGTCYz2TH0dfnyZQwZMgR+fn4MGQ1Qq9XQaDRSl2EQa2vrRn/XxmTK/0aI9MFwQ/SbyZMn49VXX0VOTg5kMhkCAwMB1LawvPLKK4iNjYW7uzuioqIAAMuXL8fDDz8MR0dH+Pv746WXXkJZWZnOPpOSkjBo0CA4ODigffv2GDp0KG7evInJkyfj0KFDWLlyJWQyGWQyGa5cudJgl8CXX36Jbt26QaFQIDAwEMuWLdM5RmBgIP7v//4PU6dOhbOzMzp27Ij169ff97tWVlZi5syZ8PT0hJ2dHR599FGcPHkSwN2ui6KiIkydOhUymazRlpvKykrMnz8f/v7+UCgUCA4OxoYNGwA03PLy1Vdf6QS306dPY/DgwXB2doaLiwvCw8ORnJyMgwcPYsqUKSguLtaen7feegsAcPPmTUycOBHt27eHg4MDhg0bhoyMDO0+6477zTffoGvXrnBwcMBzzz2H27dv4z//+Q8CAwPRvn17vPrqq1Cr1drtqqqqMH/+fHTo0AGOjo7o27cvDh482OB+w8LCoFAokJ2djYMHD6JPnz5wdHREu3btMGDAAGRnZzd67nNzc/GXv/wFrq6ucHR0REREBH788Uft52vXrkXnzp0hl8vRtWtX/Pe//9XZXiaT4d///jdGjRoFBwcHBAcHY8+ePdrPb968ieeffx4eHh6wt7dHcHAwNm3apPNn+/tuqYSEBISEhMDe3h6DBw/GlStX6tV87NgxPPbYY7C3t4e/vz9mzpyJ27dvaz8PDAzEu+++i8mTJ0OpVGLGjBl6bVdQUIARI0bA3t4enTp1wtatWxs9b0QGMfmjOYnMxK1bt8SiRYuEn5+fUKlUoqCgQAhR+9RxJycnMW/ePHH+/HmRnp4uhBBixYoV4sCBAyIzM1Ps379fdO3aVbz44ova/aWmpgqFQiFefPFFkZaWJn755Rfx0UcfiV9//VXcunVL9O/fX8yYMUOoVCqhUqlETU2N9om7N2/eFEIIkZycLKysrMSiRYvEhQsXxKZNm4S9vb3YtGmT9jgBAQHC1dVVrF69WmRkZIjFixcLKysrbZ0NmTlzpvD19RUJCQni7NmzYtKkSaJ9+/aiqKhI1NTUCJVKJVxcXER8fLxQqVSNPpF6zJgxwt/fX+zatUtcvnxZfP/99+Lzzz8XQgixadMmoVQqddbfvXu3+P3/drp16ybGjx8v0tPTxcWLF8WOHTtEWlqaqKysFPHx8cLFxUV7fkpLS4UQQvzxj38UoaGh4vDhwyItLU0MHTpUdOnSRVRVVWmPa2trK6KiosSpU6fEoUOHhJubm4iOjhZjxowRZ8+eFV9//bWQy+XaWoUQYty4cSIyMlIcPnxYXLp0SSxdulQoFApx8eJFnf1GRkaKpKQkcf78eXHr1i2hVCrF3LlzxaVLl8S5c+fE5s2bRXZ2doPnq7S0VAQFBYmBAweKI0eOiIyMDLF9+3Zx7NgxIYQQu3btEra2tmL16tXiwoULYtmyZcLa2locOHBAuw8Aws/PT3z22WciIyNDzJw5Uzg5OYmioiIhhBAvv/yy6NWrlzh58qTIysoSiYmJYs+ePUIIIbKysgQAkZqaKoQQIicnRygUCjFr1ixx/vx58emnnwovLy+d3+CZM2eEk5OTWLFihbh48aJISkoSjzzyiJg8ebK2poCAAOHi4iKWLl0qMjIyREZGhl7bDRs2THTv3l0cO3ZMJCcni8jISGFvby9WrFjR4Pkj0hfDDdHvrFixQgQEBOgsGzRokOjVq1eT2+7YsUO4ublp3//1r38VAwYMaHT9QYMGiVmzZuksuzfcjBs3TkRFRemsM2/ePBEWFqZ9HxAQIMaPH699r9FohKenp1i7dm2Dxy0rKxO2trZi69at2mVVVVXC19dXLFmyRLtMqVTqhKh7XbhwQQAQiYmJDX6uT7hxdnYWmzdv1nv7ixcvCgAiKSlJu6ywsFDY29uLHTt2aLcDIC5duqRd54UXXhAODg7agCSEEEOHDhUvvPCCEEKIS5cuCZlMJq5du6ZzvCeeeELExcXp7DctLU37eVFRkQAgDh482OB3uNfHH38snJ2dtUHkXpGRkWLGjBk6y/785z+L4cOHa98DEP/4xz+078vKyoRMJhPffvutEEKIESNGiClTpjS4/3vDTVxcnAgNDRUajUa7zuuvv67zG5wwYYL429/+prOfI0eOCCsrK3Hnzh0hRO1vcOTIkTrrNLVd3e/nxIkT2s/T09MFAIYbemDsliLSQ0RERL1lP/zwA6KiotChQwc4Oztj4sSJKCoq0ja7p6Wl4Yknnnig46anp2PAgAE6ywYMGICMjAydLpUePXpo/10mk8Hb2xsFBQUN7vPy5cuorq7W2a+trS369OmD9PR0vWtLS0uDtbU1Bg0apPc294qNjcX06dPx5JNP4v3338fly5fvu356ejpsbGzQt29f7TI3Nzd07dpVp3YHBwd07txZ+97LywuBgYFwcnLSWVZ3jk6dOgUhBEJCQuDk5KR9HTp0SKcmuVyuc65dXV0xefJkDB06FCNGjMDKlSuhUqkarT8tLQ2PPPIIXF1dG/1+Df153/vn8vsaHB0d4ezsrP0uL774Ij7//HP06tUL8+fPx7FjxxqtJz09Hf369dPpKuzfv7/OOikpKdi8ebPOeRk6dCg0Gg2ysrK0693730hT29X9Wf5+u4ceeojju8goGG6I9ODo6KjzPjs7G8OHD0f37t3x5ZdfIiUlBatXrwYAVFdXAwDs7e0f+LhCiHqDi4UQ9daztbXVeS+TyRod7Fq3fUP7NWQgc1Pfz8rKql6tdeemzltvvYWzZ8/i6aefxoEDBxAWFobdu3c3us+Gvnvd8t/X3tD5uN850mg0sLa2RkpKCtLS0rSv9PR0rFy5UruNvb19vXO0adMmHD9+HJGRkdi+fTtCQkJw4sSJBuvU5zehz5/L/b7LsGHDkJ2djdmzZyMvLw9PPPEE5s6d2+CxGjufv6fRaPDCCy/onJfTp08jIyNDJ0De+99IU9s19jskMgaGG6JmSE5ORk1NDZYtW4Z+/fohJCQEeXl5Ouv06NED+/fvb3Qfcrlcp/WlIWFhYTh69KjOsmPHjiEkJATW1tbNqr1Lly6Qy+U6+62urkZycjJCQ0P13s/DDz8MjUaDQ4cONfi5h4cHSktLdQaQNjS/SkhICObMmYN9+/Zh9OjR2sGvDZ2fsLAw1NTU6AzALSoqwsWLFw2q/V6PPPII1Go1CgoK0KVLF52Xt7e3XtvHxcXh2LFj6N69Oz777LMG1+vRowfS0tJw48aNBj8PDQ1t8M/b0O/m4eGByZMn49NPP0V8fHyjA8zDwsLqBbF73/fu3Rtnz56td17qfkeNaWq70NBQ1NTUIDk5WbvNhQsXWsUcT2T+GG6ImqFz586oqanBRx99hMzMTPz3v//FunXrdNaJi4vDyZMn8dJLL+HMmTM4f/481q5di8LCQgC1d5j8+OOPuHLlCgoLCxtsaXnttdewf/9+vPPOO7h48SL+85//YNWqVY3+TVwfjo6OePHFFzFv3jzs3bsX586dw4wZM1BeXo5p06bpvZ/AwEBMmjQJU6dOxVdffYWsrCwcPHgQO3bsAAD07dsXDg4O+Pvf/45Lly7hs88+07nr6s6dO3jllVdw8OBBZGdnIykpCSdPntReyAMDA1FWVob9+/ejsLAQ5eXlCA4OxrPPPosZM2bg6NGjOH36NMaPH48OHTrg2WefbfY5CQkJwfPPP4+JEydi165dyMrKwsmTJ/HBBx8gISGh0e2ysrIQFxeH48ePIzs7G/v27btv0PrrX/8Kb29vjBw5EklJScjMzMSXX36J48ePAwDmzZuHzZs3Y926dcjIyMDy5cuxa9cug/6833zzTfzvf//DpUuXcPbsWXzzzTeN1hMTE4PLly8jNjYWFy5cqPdnBACvv/46jh8/jpdffhlpaWnIyMjAnj178Oqrr963jqa269q1K5566inMmDEDP/74I1JSUjB9+nSjtHgScUAx0e80NqD43oG/QgixfPly4ePjI+zt7cXQoUPFli1bdAZiCiHEwYMHRWRkpFAoFKJdu3Zi6NCh2s8vXLgg+vXrJ+zt7QUAkZWVVW9AsRBC7Ny5U4SFhQlbW1vRsWNHsXTpUp06AgIC6g3A7Nmzp1i4cGGj3/POnTvi1VdfFe7u7kKhUIgBAwaIn376SWedpgYU1+1nzpw5wsfHR8jlctGlSxexceNG7ee7d+8WXbp0EXZ2duKZZ54R69ev1w4orqysFH/5y1+Ev7+/kMvlwtfXV7zyyivaQapCCBETEyPc3NwEAO33uXHjhpgwYYJQKpXac193R5MQDQ9EXrhwoejZs6fOskmTJolnn31W+76qqkq8+eabIjAwUNja2gpvb28xatQocebMmUb3m5+fL0aOHKn9/gEBAeLNN98UarW60XN25coV8ac//Um4uLgIBwcHERERIX788Uft52vWrBFBQUHC1tZWhISEiC1btuhsD0Ds3r1bZ9nv/6zeeecdERoaKuzt7YWrq6t49tlnRWZmphCi/oBiIYT4+uuvRZcuXYRCoRADBw4UGzdurPcb/Omnn0RUVJRwcnISjo6OokePHuK9997Tft7Qb1Cf7VQqlXj66aeFQqEQHTt2FFu2bGl0X0SGkAmhR6crERERkZlgtxQRERFZFIYbIiIisigMN0RERGRRGG6IiIjIojDcEBERkUVhuCEiIiKLwnBDREREFoXhhoiIiCwKww0RERFZFIYbIiIisigMN0RERGRR/j+ILo9RuTAcYgAAAABJRU5ErkJggg==",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# graphic for cumulated revenue\n",
"\n",
"plt.figure()\n",
"plt.plot(X_test_segment.index/X_test_segment.index.max(), \n",
" np.cumsum(X_test_segment[\"total_amount\"].sort_values(ascending=False)).values/ \\\n",
" np.sum(X_test_segment[\"total_amount\"]))\n",
"plt.xlabel(\"fraction of customers considered\")\n",
"plt.ylabel(\"cumulated revenue\")\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 198,
"id": "67981e78-d7a5-432e-b93b-9d0d189f4e5d",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"96095"
]
},
"execution_count": 198,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X_test_segment.index.max()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}