In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
"
],
"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": 81,
"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": 88,
"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": 90,
"id": "846f53b9-73c2-4a8b-9d9e-f11bf59ce9ba",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_620/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_620/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_620/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_620/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": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\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",
"
fidelity
\n",
"
...
\n",
"
opt_in
\n",
"
gender_female
\n",
"
gender_male
\n",
"
gender_other
\n",
"
nb_campaigns
\n",
"
nb_campaigns_opened
\n",
"
has_purchased
\n",
"
has_purchased_estim
\n",
"
score
\n",
"
quartile
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
4.0
\n",
"
1.0
\n",
"
100.0
\n",
"
1.0
\n",
"
0.0
\n",
"
5.177187
\n",
"
5.177187
\n",
"
0.000000
\n",
"
0.0
\n",
"
1
\n",
"
...
\n",
"
False
\n",
"
1
\n",
"
0
\n",
"
0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
1.0
\n",
"
0.657671
\n",
"
3
\n",
"
\n",
"
\n",
"
1
\n",
"
1.0
\n",
"
1.0
\n",
"
55.0
\n",
"
1.0
\n",
"
0.0
\n",
"
426.265613
\n",
"
426.265613
\n",
"
0.000000
\n",
"
0.0
\n",
"
2
\n",
"
...
\n",
"
True
\n",
"
0
\n",
"
1
\n",
"
0
\n",
"
0.0
\n",
"
0.0
\n",
"
1.0
\n",
"
0.0
\n",
"
0.266538
\n",
"
2
\n",
"
\n",
"
\n",
"
2
\n",
"
17.0
\n",
"
1.0
\n",
"
80.0
\n",
"
1.0
\n",
"
0.0
\n",
"
436.033437
\n",
"
436.033437
\n",
"
0.000000
\n",
"
0.0
\n",
"
2
\n",
"
...
\n",
"
True
\n",
"
1
\n",
"
0
\n",
"
0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.214668
\n",
"
1
\n",
"
\n",
"
\n",
"
3
\n",
"
4.0
\n",
"
1.0
\n",
"
120.0
\n",
"
1.0
\n",
"
0.0
\n",
"
5.196412
\n",
"
5.196412
\n",
"
0.000000
\n",
"
0.0
\n",
"
1
\n",
"
...
\n",
"
False
\n",
"
1
\n",
"
0
\n",
"
0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
1.0
\n",
"
0.657770
\n",
"
3
\n",
"
\n",
"
\n",
"
4
\n",
"
34.0
\n",
"
2.0
\n",
"
416.0
\n",
"
1.0
\n",
"
0.0
\n",
"
478.693148
\n",
"
115.631470
\n",
"
363.061678
\n",
"
0.0
\n",
"
4
\n",
"
...
\n",
"
False
\n",
"
1
\n",
"
0
\n",
"
0
\n",
"
0.0
\n",
"
0.0
\n",
"
1.0
\n",
"
1.0
\n",
"
0.894173
\n",
"
4
\n",
"
\n",
"
\n",
"
5
\n",
"
2.0
\n",
"
1.0
\n",
"
60.0
\n",
"
1.0
\n",
"
0.0
\n",
"
5.140069
\n",
"
5.140069
\n",
"
0.000000
\n",
"
0.0
\n",
"
1
\n",
"
...
\n",
"
False
\n",
"
0
\n",
"
1
\n",
"
0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
1.0
\n",
"
0.717482
\n",
"
3
\n",
"
\n",
"
\n",
"
6
\n",
"
5.0
\n",
"
1.0
\n",
"
61.0
\n",
"
1.0
\n",
"
1.0
\n",
"
105.053773
\n",
"
105.053773
\n",
"
0.000000
\n",
"
5.0
\n",
"
1
\n",
"
...
\n",
"
False
\n",
"
0
\n",
"
0
\n",
"
1
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
1.0
\n",
"
0.541855
\n",
"
3
\n",
"
\n",
"
\n",
"
7
\n",
"
4.0
\n",
"
1.0
\n",
"
80.0
\n",
"
1.0
\n",
"
0.0
\n",
"
63.206030
\n",
"
63.206030
\n",
"
0.000000
\n",
"
0.0
\n",
"
1
\n",
"
...
\n",
"
True
\n",
"
0
\n",
"
1
\n",
"
0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.461164
\n",
"
2
\n",
"
\n",
"
\n",
"
8
\n",
"
1.0
\n",
"
1.0
\n",
"
10.0
\n",
"
1.0
\n",
"
0.0
\n",
"
44.698090
\n",
"
44.698090
\n",
"
0.000000
\n",
"
0.0
\n",
"
1
\n",
"
...
\n",
"
True
\n",
"
0
\n",
"
0
\n",
"
1
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.310828
\n",
"
2
\n",
"
\n",
"
\n",
"
9
\n",
"
3.0
\n",
"
3.0
\n",
"
165.0
\n",
"
1.0
\n",
"
1.0
\n",
"
266.012106
\n",
"
258.012106
\n",
"
8.000000
\n",
"
3.0
\n",
"
2
\n",
"
...
\n",
"
False
\n",
"
0
\n",
"
0
\n",
"
1
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.452877
\n",
"
2
\n",
"
\n",
" \n",
"
\n",
"
10 rows × 21 columns
\n",
"
"
],
"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": 90,
"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": 91,
"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": 92,
"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": 93,
"id": "2dff1def-02df-413e-afce-b4aeaf7752b6",
"metadata": {},
"outputs": [],
"source": [
"def odd_ratio(score) :\n",
" return score / (1 - score)"
]
},
{
"cell_type": "code",
"execution_count": 94,
"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": 98,
"id": "781b0d40-c954-4c54-830a-e709c8667328",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"6.172331113516847"
]
},
"execution_count": 98,
"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": 102,
"id": "248cb862-418e-4767-9933-70c4885ecf40",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"6.070461139075353"
]
},
"execution_count": 102,
"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": 103,
"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": 116,
"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": 117,
"id": "8213d0e4-063b-49fa-90b7-677fc34f4c01",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_620/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": 118,
"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": 130,
"id": "ed27a165-68d2-44f8-8cec-b12dad2cca5d",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"29169.0"
]
},
"execution_count": 130,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X_test_segment[\"has_purchased_estim\"].sum()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "761146b7-3d0d-44b1-8b91-87e6d54f1626",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 119,
"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": 208,
"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": [
"
"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# visualization\n",
"\n",
"# histogramme des probas et des probas ajustées\n",
"\n",
"def plot_comp_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_comp_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": 121,
"id": "c618cebc-c295-47f7-bd76-b7e18778a17c",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
"
],
"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": "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": [
"