From d3e13f4c56462368c67b56d83d35d59cac935ed7 Mon Sep 17 00:00:00 2001 From: tpique-ensae Date: Wed, 27 Mar 2024 17:58:30 +0000 Subject: [PATCH] completed CA projection --- 0_7_CA_segment.py | 64 +- Sport/Modelization/CA_segment_sport.ipynb | 2966 +++++++++++++-------- utils_CA_segment.py | 91 + 3 files changed, 1929 insertions(+), 1192 deletions(-) diff --git a/0_7_CA_segment.py b/0_7_CA_segment.py index 9d8e7fe..a446a26 100644 --- a/0_7_CA_segment.py +++ b/0_7_CA_segment.py @@ -4,47 +4,55 @@ from pandas import DataFrame import numpy as np import os import s3fs -import re -from sklearn.linear_model import LogisticRegression -from sklearn.ensemble import RandomForestClassifier -from sklearn.metrics import accuracy_score, confusion_matrix, classification_report, recall_score -from sklearn.utils import class_weight -from sklearn.neighbors import KNeighborsClassifier -from sklearn.pipeline import Pipeline -from sklearn.compose import ColumnTransformer -from sklearn.preprocessing import OneHotEncoder -from sklearn.impute import SimpleImputer -from sklearn.model_selection import GridSearchCV -from sklearn.preprocessing import StandardScaler, MaxAbsScaler, MinMaxScaler -from sklearn.metrics import make_scorer, f1_score, balanced_accuracy_score -import seaborn as sns import matplotlib.pyplot as plt -from sklearn.metrics import roc_curve, auc, precision_recall_curve, average_precision_score -from sklearn.exceptions import ConvergenceWarning, DataConversionWarning -from sklearn.naive_bayes import GaussianNB from scipy.optimize import fsolve import pickle import warnings import io +# importation of functions defined +from utils_CA_segment import * + +# Create filesystem object +S3_ENDPOINT_URL = "https://" + os.environ["AWS_S3_ENDPOINT"] +fs = s3fs.S3FileSystem(client_kwargs={'endpoint_url': S3_ENDPOINT_URL}) + # define type of activity type_of_activity = "sport" PATH = f"projet-bdc2324-team1/Output_expected_CA/{type_of_activity}/" +# type of model for the score +type_of_model = "LogisticRegression_cv" + +# load train and test sets +dataset_train, dataset_test = load_train_test(type_of_activity) + +# make features - define X train and X test +X_train, X_test, y_train, y_test = features_target_split(dataset_train, dataset_test) + +# choose model - logit cross validated +model = load_model(type_of_activity, type_of_model) + +# create table X test segment from X test +X_test_segment = df_segment(X_test, y_test, model) + # comparison with bias of the train set - X train to be defined -X_train_score = logit_cv.predict_proba(X_train)[:, 1] +X_train_score = model.predict_proba(X_train)[:, 1] bias_train_set = find_bias(odd_ratios = odd_ratio(adjust_score_1(X_train_score)), y_objective = y_train["y_has_purchased"].sum(), initial_guess=6) +# create a score adjusted with the bias computed score_adjusted_train = adjusted_score(odd_ratio(adjust_score_1(X_test_segment["score"])), bias = bias_train_set) X_test_segment["score_adjusted"] = score_adjusted_train -# plot adjusted scores and save (to be tested) +### 1. plot adjusted scores and save (to be tested) plot_hist_scores(X_test_segment, score = "score", score_adjusted = "score_adjusted", type_of_activity = type_of_activity) +save_file_s3_ca("hist_score_adjusted_", type_of_activity) +""" image_buffer = io.BytesIO() plt.savefig(image_buffer, format='png') image_buffer.seek(0) @@ -53,27 +61,33 @@ FILE_PATH_OUT_S3 = PATH + file_name + type_of_activity + ".png" with fs.open(FILE_PATH_OUT_S3, 'wb') as s3_file: s3_file.write(image_buffer.read()) plt.close() +""" -# comparison between score and adjusted score +### 2. comparison between score and adjusted score X_test_table_adjusted_scores = (100 * X_test_segment.groupby("quartile")[["score","score_adjusted", "has_purchased"]].mean()).round(2).reset_index() X_test_table_adjusted_scores = X_test_table_adjusted_scores.rename(columns = {col : f"{col} (%)" for col in X_test_table_adjusted_scores.columns if col in ["score","score_adjusted", "has_purchased"]}) -file_name = "table_adjusted_score" +# save table +file_name = "table_adjusted_score_" FILE_PATH_OUT_S3 = PATH + file_name + type_of_activity + ".csv" with fs.open(FILE_PATH_OUT_S3, 'w') as file_out: X_test_table_adjusted_scores.to_csv(file_out, index = False) # project revenue -X_test_segment = project_tickets_CA (X_test_segment, "nb_tickets", "total_amount", "score_adjusted", duration_ref=1.5, duration_projection=1) +X_test_segment = project_tickets_CA (X_test_segment, "nb_tickets", "total_amount", "score_adjusted", duration_ref=17, duration_projection=12) -# table summarizing projections +### 3. table summarizing projections (nb tickets, revenue) X_test_expected_CA = round(summary_expected_CA(df=X_test_segment, segment="quartile", nb_tickets_expected="nb_tickets_expected", total_amount_expected="total_amount_expected", total_amount="total_amount"),2) -file_name = "table_expected_CA" +# rename columns +mapping_dict = {col: col.replace("perct", "(%)").replace("_", " ") for col in X_test_expected_CA.columns} +X_test_expected_CA = X_test_expected_CA.rename(columns=mapping_dict) + +# save table +file_name = "table_expected_CA_" FILE_PATH_OUT_S3 = PATH + file_name + type_of_activity + ".csv" with fs.open(FILE_PATH_OUT_S3, 'w') as file_out: X_test_expected_CA.to_csv(file_out, index = False) - diff --git a/Sport/Modelization/CA_segment_sport.ipynb b/Sport/Modelization/CA_segment_sport.ipynb index 1d4e90c..47786a6 100644 --- a/Sport/Modelization/CA_segment_sport.ipynb +++ b/Sport/Modelization/CA_segment_sport.ipynb @@ -75,13 +75,23 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 31, + "id": "d6017ed0-6233-4888-85a7-05dec50a255b", + "metadata": {}, + "outputs": [], + "source": [ + "type_of_activity = \"musique\"" + ] + }, + { + "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", + "def load_train_test(type_of_activity):\n", + " BUCKET = f\"projet-bdc2324-team1/Generalization/{type_of_activity}\"\n", " File_path_train = BUCKET + \"/Train_set.csv\"\n", " File_path_test = BUCKET + \"/Test_set.csv\"\n", " \n", @@ -98,7 +108,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 32, "id": "2831d546-b365-498b-8248-c618bd9c3057", "metadata": {}, "outputs": [ @@ -106,8 +116,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "/tmp/ipykernel_521/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" + "/tmp/ipykernel_1080/2350085345.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", + "/tmp/ipykernel_1080/2350085345.py:11: DtypeWarning: Columns (38) have mixed types. Specify dtype option on import or set low_memory=False.\n", + " dataset_test = pd.read_csv(file_in, sep=\",\")\n" ] }, { @@ -124,51 +136,51 @@ "time_between_purchase 0\n", "nb_tickets_internet 0\n", "street_id 0\n", - "structure_id 222825\n", - "mcp_contact_id 70874\n", + "structure_id 327067\n", + "mcp_contact_id 135224\n", "fidelity 0\n", "tenant_id 0\n", "is_partner 0\n", - "deleted_at 224213\n", + "deleted_at 354365\n", "gender 0\n", "is_email_true 0\n", "opt_in 0\n", - "last_buying_date 66139\n", - "max_price 66139\n", + "last_buying_date 119201\n", + "max_price 119201\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", + "average_price 115193\n", + "average_purchase_delay 119203\n", + "average_price_basket 119203\n", + "average_ticket_basket 119203\n", + "total_price 4008\n", "purchase_count 0\n", - "first_buying_date 66139\n", - "country 23159\n", + "first_buying_date 119201\n", + "country 56856\n", "gender_label 0\n", "gender_female 0\n", "gender_male 0\n", "gender_other 0\n", - "country_fr 23159\n", + "country_fr 56856\n", "nb_campaigns 0\n", "nb_campaigns_opened 0\n", - "time_to_open 123159\n", + "time_to_open 224310\n", "y_has_purchased 0\n", "dtype: int64" ] }, - "execution_count": 4, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "dataset_train, dataset_test = load_train_test()\n", + "dataset_train, dataset_test = load_train_test(type_of_activity)\n", "dataset_train.isna().sum()" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "b8827f7b-b304-4f51-9814-c7a98ed88cf0", "metadata": {}, "outputs": [], @@ -196,7 +208,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 33, "id": "c18195fc-ed40-4e39-a59e-c9ecc5a8e6c3", "metadata": {}, "outputs": [ @@ -204,8 +216,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "Shape train : (224213, 17)\n", - "Shape test : (96096, 17)\n" + "Shape train : (354365, 17)\n", + "Shape test : (151874, 17)\n" ] } ], @@ -225,7 +237,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "id": "7c81390e-598c-4f02-bd56-dd03b00dcb33", "metadata": {}, "outputs": [ @@ -272,102 +284,102 @@ " \n", " \n", " 0\n", - " 4.0\n", + " 2.0\n", " 1.0\n", - " 100.00\n", + " 22.0\n", " 1.0\n", - " 0.0\n", - " 5.177187\n", - " 5.177187\n", + " 1.0\n", + " 307.203553\n", + " 307.203553\n", " 0.000000\n", - " 0.0\n", + " 2.0\n", " 1\n", " True\n", " False\n", + " 0\n", + " 0\n", " 1\n", - " 0\n", - " 0\n", " 0.0\n", " 0.0\n", " \n", " \n", " 1\n", + " 269.0\n", + " 8.0\n", + " 50.0\n", + " 2.0\n", " 1.0\n", - " 1.0\n", - " 55.00\n", - " 1.0\n", - " 0.0\n", - " 426.265613\n", - " 426.265613\n", - " 0.000000\n", - " 0.0\n", - " 2\n", + " 378.208090\n", + " 39.389595\n", + " 338.818495\n", + " 66.0\n", + " 10\n", " True\n", " True\n", " 0\n", + " 0\n", " 1\n", - " 0\n", - " 0.0\n", - " 0.0\n", + " 65.0\n", + " 1.0\n", " \n", " \n", " 2\n", - " 17.0\n", - " 1.0\n", - " 80.00\n", - " 1.0\n", " 0.0\n", - " 436.033437\n", - " 436.033437\n", - " 0.000000\n", " 0.0\n", - " 2\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 550.000000\n", + " 550.000000\n", + " -1.000000\n", + " 0.0\n", + " 0\n", " True\n", " True\n", + " 0\n", " 1\n", " 0\n", - " 0\n", - " 0.0\n", - " 0.0\n", + " 4.0\n", + " 2.0\n", " \n", " \n", " 3\n", - " 4.0\n", - " 1.0\n", - " 120.00\n", - " 1.0\n", " 0.0\n", - " 5.196412\n", - " 5.196412\n", - " 0.000000\n", " 0.0\n", - " 1\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 550.000000\n", + " 550.000000\n", + " -1.000000\n", + " 0.0\n", + " 0\n", + " True\n", " True\n", - " False\n", " 1\n", " 0\n", " 0\n", - " 0.0\n", + " 2.0\n", " 0.0\n", " \n", " \n", " 4\n", - " 34.0\n", - " 2.0\n", - " 416.00\n", - " 1.0\n", " 0.0\n", - " 478.693148\n", - " 115.631470\n", - " 363.061678\n", " 0.0\n", - " 4\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 550.000000\n", + " 550.000000\n", + " -1.000000\n", + " 0.0\n", + " 0\n", " True\n", - " False\n", + " True\n", + " 0\n", + " 0\n", " 1\n", - " 0\n", - " 0\n", - " 0.0\n", + " 4.0\n", " 0.0\n", " \n", " \n", @@ -391,180 +403,180 @@ " ...\n", " \n", " \n", - " 96091\n", + " 186115\n", + " 4.0\n", " 1.0\n", + " 96.0\n", " 1.0\n", - " 67.31\n", - " 1.0\n", - " 1.0\n", - " 278.442257\n", - " 278.442257\n", + " 0.0\n", + " 117.364572\n", + " 117.364572\n", " 0.000000\n", - " 1.0\n", - " 2\n", - " True\n", - " False\n", - " 0\n", - " 1\n", - " 0\n", - " 15.0\n", - " 5.0\n", - " \n", - " \n", - " 96092\n", - " 1.0\n", - " 1.0\n", - " 61.41\n", - " 1.0\n", - " 1.0\n", - " 189.207373\n", - " 189.207373\n", - " 0.000000\n", - " 1.0\n", + " 0.0\n", " 1\n", " True\n", " False\n", - " 0\n", " 1\n", " 0\n", - " 12.0\n", - " 9.0\n", + " 0\n", + " 1.0\n", + " 0.0\n", " \n", " \n", - " 96093\n", + " 186116\n", + " 0.0\n", " 0.0\n", " 0.0\n", - " 0.00\n", " 0.0\n", " 0.0\n", " 550.000000\n", " 550.000000\n", " -1.000000\n", " 0.0\n", - " 1\n", + " 0\n", " True\n", " True\n", + " 0\n", " 1\n", " 0\n", - " 0\n", - " 29.0\n", - " 3.0\n", + " 46.0\n", + " 13.0\n", " \n", " \n", - " 96094\n", - " 1.0\n", - " 1.0\n", - " 79.43\n", - " 1.0\n", - " 1.0\n", - " 279.312905\n", - " 279.312905\n", - " 0.000000\n", - " 1.0\n", - " 1\n", - " True\n", - " False\n", - " 0\n", - " 1\n", - " 0\n", - " 20.0\n", - " 4.0\n", - " \n", - " \n", - " 96095\n", + " 186117\n", + " 0.0\n", " 0.0\n", " 0.0\n", - " 0.00\n", " 0.0\n", " 0.0\n", " 550.000000\n", " 550.000000\n", " -1.000000\n", " 0.0\n", - " 2\n", + " 0\n", + " True\n", " True\n", - " False\n", " 0\n", " 1\n", " 0\n", - " 31.0\n", - " 4.0\n", + " 84.0\n", + " 24.0\n", + " \n", + " \n", + " 186118\n", + " 1.0\n", + " 1.0\n", + " 0.0\n", + " 1.0\n", + " 0.0\n", + " 165.538391\n", + " 165.538391\n", + " 0.000000\n", + " 0.0\n", + " 1\n", + " True\n", + " False\n", + " 1\n", + " 0\n", + " 0\n", + " 1.0\n", + " 0.0\n", + " \n", + " \n", + " 186119\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 550.000000\n", + " 550.000000\n", + " -1.000000\n", + " 0.0\n", + " 0\n", + " True\n", + " True\n", + " 0\n", + " 0\n", + " 1\n", + " 47.0\n", + " 21.0\n", " \n", " \n", "\n", - "

96096 rows × 17 columns

\n", + "

186120 rows × 17 columns

\n", "" ], "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", + " nb_tickets nb_purchases total_amount nb_suppliers \\\n", + "0 2.0 1.0 22.0 1.0 \n", + "1 269.0 8.0 50.0 2.0 \n", + "2 0.0 0.0 0.0 0.0 \n", + "3 0.0 0.0 0.0 0.0 \n", + "4 0.0 0.0 0.0 0.0 \n", + "... ... ... ... ... \n", + "186115 4.0 1.0 96.0 1.0 \n", + "186116 0.0 0.0 0.0 0.0 \n", + "186117 0.0 0.0 0.0 0.0 \n", + "186118 1.0 1.0 0.0 1.0 \n", + "186119 0.0 0.0 0.0 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", + " vente_internet_max purchase_date_min purchase_date_max \\\n", + "0 1.0 307.203553 307.203553 \n", + "1 1.0 378.208090 39.389595 \n", + "2 0.0 550.000000 550.000000 \n", + "3 0.0 550.000000 550.000000 \n", + "4 0.0 550.000000 550.000000 \n", + "... ... ... ... \n", + "186115 0.0 117.364572 117.364572 \n", + "186116 0.0 550.000000 550.000000 \n", + "186117 0.0 550.000000 550.000000 \n", + "186118 0.0 165.538391 165.538391 \n", + "186119 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", + " time_between_purchase nb_tickets_internet fidelity is_email_true \\\n", + "0 0.000000 2.0 1 True \n", + "1 338.818495 66.0 10 True \n", + "2 -1.000000 0.0 0 True \n", + "3 -1.000000 0.0 0 True \n", + "4 -1.000000 0.0 0 True \n", + "... ... ... ... ... \n", + "186115 0.000000 0.0 1 True \n", + "186116 -1.000000 0.0 0 True \n", + "186117 -1.000000 0.0 0 True \n", + "186118 0.000000 0.0 1 True \n", + "186119 -1.000000 0.0 0 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", + " opt_in gender_female gender_male gender_other nb_campaigns \\\n", + "0 False 0 0 1 0.0 \n", + "1 True 0 0 1 65.0 \n", + "2 True 0 1 0 4.0 \n", + "3 True 1 0 0 2.0 \n", + "4 True 0 0 1 4.0 \n", + "... ... ... ... ... ... \n", + "186115 False 1 0 0 1.0 \n", + "186116 True 0 1 0 46.0 \n", + "186117 True 0 1 0 84.0 \n", + "186118 False 1 0 0 1.0 \n", + "186119 True 0 0 1 47.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", + " nb_campaigns_opened \n", + "0 0.0 \n", + "1 1.0 \n", + "2 2.0 \n", + "3 0.0 \n", + "4 0.0 \n", + "... ... \n", + "186115 0.0 \n", + "186116 13.0 \n", + "186117 24.0 \n", + "186118 0.0 \n", + "186119 21.0 \n", "\n", - "[96096 rows x 17 columns]" + "[186120 rows x 17 columns]" ] }, - "execution_count": 7, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -575,7 +587,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "id": "c708f439-bb75-4688-bf4f-4c04e13deaae", "metadata": {}, "outputs": [], @@ -593,14 +605,14 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 34, "id": "5261a803-05b8-41a0-968c-dc7bde48ddd3", "metadata": {}, "outputs": [ { "data": { "text/html": [ - "
GridSearchCV(cv=3, error_score='raise',\n",
+       "
GridSearchCV(cv=3, error_score='raise',\n",
        "             estimator=Pipeline(steps=[('preprocessor',\n",
        "                                        ColumnTransformer(transformers=[('num',\n",
        "                                                                         Pipeline(steps=[('scaler',\n",
@@ -1025,10 +1037,10 @@
        "       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",
+       "                                                                 {0.0: 0.5481283836040216,\n",
+       "                                                                  1.0: 5.694439980716696}],\n",
        "                         'LogisticRegression_cv__penalty': ['l1', 'l2']},\n",
-       "             scoring=make_scorer(recall_score, response_method='predict'))
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.
['nb_tickets', 'nb_purchases', 'total_amount', 'nb_suppliers', 'vente_internet_max', 'purchase_date_min', 'purchase_date_max', 'time_between_purchase', 'nb_tickets_internet', 'nb_campaigns', 'nb_campaigns_opened']
StandardScaler()
['opt_in', 'gender_male', 'gender_female']
OneHotEncoder(handle_unknown='ignore', sparse_output=False)
LogisticRegression(max_iter=5000, solver='saga')
" ], "text/plain": [ "GridSearchCV(cv=3, error_score='raise',\n", @@ -1109,19 +1121,19 @@ " 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", + " {0.0: 0.5481283836040216,\n", + " 1.0: 5.694439980716696}],\n", " 'LogisticRegression_cv__penalty': ['l1', 'l2']},\n", " scoring=make_scorer(recall_score, response_method='predict'))" ] }, - "execution_count": 9, + "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "logit_cv = load_model(\"sport\", \"LogisticRegression_cv\")\n", + "logit_cv = load_model(type_of_activity, \"LogisticRegression_cv\")\n", "logit_cv" ] }, @@ -1135,7 +1147,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 35, "id": "018d8ff4-3436-4eec-8507-d1a265cbabf1", "metadata": {}, "outputs": [], @@ -1146,7 +1158,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 48, "id": "846f53b9-73c2-4a8b-9d9e-f11bf59ce9ba", "metadata": {}, "outputs": [ @@ -1154,25 +1166,25 @@ "name": "stderr", "output_type": "stream", "text": [ - "/tmp/ipykernel_521/375041546.py:3: SettingWithCopyWarning: \n", + "/tmp/ipykernel_1080/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_521/375041546.py:4: SettingWithCopyWarning: \n", + "/tmp/ipykernel_1080/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_521/375041546.py:5: SettingWithCopyWarning: \n", + "/tmp/ipykernel_1080/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_521/375041546.py:6: SettingWithCopyWarning: \n", + "/tmp/ipykernel_1080/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", @@ -1212,7 +1224,6 @@ " nb_tickets_internet\n", " fidelity\n", " ...\n", - " opt_in\n", " gender_female\n", " gender_male\n", " gender_other\n", @@ -1222,319 +1233,320 @@ " has_purchased_estim\n", " score\n", " quartile\n", + " score_adjusted\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", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 550.000000\n", + " 550.000000\n", + " -1.0\n", + " 0.0\n", + " 2\n", " ...\n", - " False\n", " 1\n", " 0\n", " 0\n", + " 2.0\n", " 0.0\n", " 0.0\n", " 0.0\n", - " 1.0\n", - " 0.657671\n", - " 3\n", + " 0.425710\n", + " 2\n", + " 0.068441\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", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 550.000000\n", + " 550.000000\n", + " -1.0\n", + " 0.0\n", + " 1\n", " ...\n", - " True\n", - " 0\n", " 1\n", " 0\n", - " 0.0\n", - " 0.0\n", + " 0\n", + " 2.0\n", " 1.0\n", " 0.0\n", - " 0.266538\n", + " 0.0\n", + " 0.442888\n", " 2\n", + " 0.073036\n", " \n", " \n", " 2\n", - " 17.0\n", + " 4.0\n", " 1.0\n", - " 80.0\n", + " 40.0\n", " 1.0\n", " 0.0\n", - " 436.033437\n", - " 436.033437\n", - " 0.000000\n", + " 508.227674\n", + " 508.227674\n", " 0.0\n", - " 2\n", + " 0.0\n", + " 4\n", " ...\n", - " True\n", " 1\n", " 0\n", " 0\n", + " 12.0\n", + " 5.0\n", " 0.0\n", " 0.0\n", - " 0.0\n", - " 0.0\n", - " 0.214668\n", - " 1\n", + " 0.293107\n", + " 2\n", + " 0.039474\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", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 550.000000\n", + " 550.000000\n", + " -1.0\n", + " 0.0\n", + " 0\n", " ...\n", - " False\n", + " 0\n", + " 0\n", " 1\n", - " 0\n", - " 0\n", + " 10.0\n", " 0.0\n", " 0.0\n", " 0.0\n", - " 1.0\n", - " 0.657770\n", - " 3\n", + " 0.062345\n", + " 1\n", + " 0.006547\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", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 550.000000\n", + " 550.000000\n", + " -1.0\n", + " 0.0\n", + " 0\n", " ...\n", - " False\n", " 1\n", " 0\n", " 0\n", + " 1.0\n", " 0.0\n", " 0.0\n", - " 1.0\n", - " 1.0\n", - " 0.894173\n", - " 4\n", + " 0.0\n", + " 0.421351\n", + " 2\n", + " 0.067312\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", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 550.000000\n", + " 550.000000\n", + " -1.0\n", + " 0.0\n", + " 0\n", " ...\n", - " False\n", + " 0\n", " 0\n", " 1\n", - " 0\n", + " 2.0\n", " 0.0\n", " 0.0\n", " 0.0\n", - " 1.0\n", - " 0.717482\n", - " 3\n", + " 0.248352\n", + " 1\n", + " 0.031709\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", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 550.000000\n", + " 550.000000\n", + " -1.0\n", + " 0.0\n", + " 0\n", " ...\n", - " False\n", " 0\n", " 0\n", " 1\n", + " 2.0\n", " 0.0\n", " 0.0\n", " 0.0\n", - " 1.0\n", - " 0.541855\n", - " 3\n", + " 0.054499\n", + " 1\n", + " 0.005680\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", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 550.000000\n", + " 550.000000\n", + " -1.0\n", + " 0.0\n", + " 0\n", " ...\n", - " True\n", + " 0\n", " 0\n", " 1\n", - " 0\n", + " 6.0\n", " 0.0\n", " 0.0\n", " 0.0\n", - " 0.0\n", - " 0.461164\n", - " 2\n", + " 0.058298\n", + " 1\n", + " 0.006098\n", " \n", " \n", " 8\n", + " 6.0\n", + " 1.0\n", + " 126.0\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", + " 390.374005\n", + " 390.374005\n", " 0.0\n", + " 6.0\n", " 1\n", " ...\n", - " True\n", - " 0\n", " 0\n", " 1\n", + " 0\n", + " 4.0\n", " 0.0\n", " 0.0\n", " 0.0\n", - " 0.0\n", - " 0.310828\n", - " 2\n", + " 0.098137\n", + " 1\n", + " 0.010670\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", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 0.0\n", + " 550.000000\n", + " 550.000000\n", + " -1.0\n", + " 0.0\n", + " 0\n", " ...\n", - " False\n", " 0\n", " 0\n", " 1\n", + " 10.0\n", " 0.0\n", " 0.0\n", " 0.0\n", - " 0.0\n", - " 0.452877\n", - " 2\n", + " 0.062345\n", + " 1\n", + " 0.006547\n", " \n", " \n", "\n", - "

10 rows × 21 columns

\n", + "

10 rows × 22 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", + "0 0.0 0.0 0.0 0.0 0.0 \n", + "1 0.0 0.0 0.0 0.0 0.0 \n", + "2 4.0 1.0 40.0 1.0 0.0 \n", + "3 0.0 0.0 0.0 0.0 0.0 \n", + "4 0.0 0.0 0.0 0.0 0.0 \n", + "5 0.0 0.0 0.0 0.0 0.0 \n", + "6 0.0 0.0 0.0 0.0 0.0 \n", + "7 0.0 0.0 0.0 0.0 0.0 \n", + "8 6.0 1.0 126.0 1.0 1.0 \n", + "9 0.0 0.0 0.0 0.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", - "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", + "0 550.000000 550.000000 -1.0 \n", + "1 550.000000 550.000000 -1.0 \n", + "2 508.227674 508.227674 0.0 \n", + "3 550.000000 550.000000 -1.0 \n", + "4 550.000000 550.000000 -1.0 \n", + "5 550.000000 550.000000 -1.0 \n", + "6 550.000000 550.000000 -1.0 \n", + "7 550.000000 550.000000 -1.0 \n", + "8 390.374005 390.374005 0.0 \n", + "9 550.000000 550.000000 -1.0 \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", + " nb_tickets_internet fidelity ... gender_female gender_male \\\n", + "0 0.0 2 ... 1 0 \n", + "1 0.0 1 ... 1 0 \n", + "2 0.0 4 ... 1 0 \n", + "3 0.0 0 ... 0 0 \n", + "4 0.0 0 ... 1 0 \n", + "5 0.0 0 ... 0 0 \n", + "6 0.0 0 ... 0 0 \n", + "7 0.0 0 ... 0 0 \n", + "8 6.0 1 ... 0 1 \n", + "9 0.0 0 ... 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", + "0 0 2.0 0.0 0.0 \n", + "1 0 2.0 1.0 0.0 \n", + "2 0 12.0 5.0 0.0 \n", + "3 1 10.0 0.0 0.0 \n", + "4 0 1.0 0.0 0.0 \n", + "5 1 2.0 0.0 0.0 \n", + "6 1 2.0 0.0 0.0 \n", + "7 1 6.0 0.0 0.0 \n", + "8 0 4.0 0.0 0.0 \n", + "9 1 10.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", + " has_purchased_estim score quartile score_adjusted \n", + "0 0.0 0.425710 2 0.068441 \n", + "1 0.0 0.442888 2 0.073036 \n", + "2 0.0 0.293107 2 0.039474 \n", + "3 0.0 0.062345 1 0.006547 \n", + "4 0.0 0.421351 2 0.067312 \n", + "5 0.0 0.248352 1 0.031709 \n", + "6 0.0 0.054499 1 0.005680 \n", + "7 0.0 0.058298 1 0.006098 \n", + "8 0.0 0.098137 1 0.010670 \n", + "9 0.0 0.062345 1 0.006547 \n", "\n", - "[10 rows x 21 columns]" + "[10 rows x 22 columns]" ] }, - "execution_count": 11, + "execution_count": 48, "metadata": {}, "output_type": "execute_result" } @@ -1551,6 +1563,471 @@ "X_test_segment.head(10)" ] }, + { + "cell_type": "code", + "execution_count": 50, + "id": "fb592fe3-ea40-4e83-8fe9-c52b9ee42f2a", + "metadata": {}, + "outputs": [], + "source": [ + "def df_segment(df, y, model) :\n", + "\n", + " y_pred = model.predict(df)\n", + " y_pred_prob = model.predict_proba(df)[:, 1]\n", + "\n", + " df_segment = df\n", + "\n", + " df_segment[\"has_purchased\"] = y\n", + " df_segment[\"has_purchased_estim\"] = y_pred\n", + " df_segment[\"score\"] = y_pred_prob\n", + " df_segment[\"quartile\"] = np.where(df_segment['score']<0.25, '1',\n", + " np.where(df_segment['score']<0.5, '2',\n", + " np.where(df_segment['score']<0.75, '3', '4')))\n", + "\n", + " return df_segment" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "968645d5-58cc-485a-bd8b-99f4cfc26fec", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_1080/2624515794.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_segment[\"has_purchased\"] = y\n", + "/tmp/ipykernel_1080/2624515794.py:9: 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_segment[\"has_purchased_estim\"] = y_pred\n", + "/tmp/ipykernel_1080/2624515794.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_segment[\"score\"] = y_pred_prob\n", + "/tmp/ipykernel_1080/2624515794.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_segment[\"quartile\"] = np.where(df_segment['score']<0.25, '1',\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nb_ticketsnb_purchasestotal_amountnb_suppliersvente_internet_maxpurchase_date_minpurchase_date_maxtime_between_purchasenb_tickets_internetfidelity...gender_femalegender_malegender_othernb_campaignsnb_campaigns_openedhas_purchasedhas_purchased_estimscorequartilescore_adjusted
00.00.00.00.00.0550.000000550.000000-1.00.02...1002.00.00.00.00.42571020.068441
10.00.00.00.00.0550.000000550.000000-1.00.01...1002.01.00.00.00.44288820.073036
24.01.040.01.00.0508.227674508.2276740.00.04...10012.05.00.00.00.29310720.039474
30.00.00.00.00.0550.000000550.000000-1.00.00...00110.00.00.00.00.06234510.006547
40.00.00.00.00.0550.000000550.000000-1.00.00...1001.00.00.00.00.42135120.067312
..................................................................
1518690.00.00.00.00.0550.000000550.000000-1.00.00...0011.01.00.00.00.25820020.033348
1518700.00.00.00.00.0550.000000550.000000-1.00.00...0108.04.00.01.00.53812430.103520
1518710.00.00.00.00.0550.000000550.000000-1.00.01...10014.04.00.01.00.54848830.107461
1518720.00.00.00.00.0550.000000550.000000-1.00.00...01016.03.00.00.00.17940010.021208
1518730.00.00.00.00.0550.000000550.000000-1.00.00...01011.08.00.00.00.22096610.027343
\n", + "

151874 rows × 22 columns

\n", + "
" + ], + "text/plain": [ + " nb_tickets nb_purchases total_amount nb_suppliers \\\n", + "0 0.0 0.0 0.0 0.0 \n", + "1 0.0 0.0 0.0 0.0 \n", + "2 4.0 1.0 40.0 1.0 \n", + "3 0.0 0.0 0.0 0.0 \n", + "4 0.0 0.0 0.0 0.0 \n", + "... ... ... ... ... \n", + "151869 0.0 0.0 0.0 0.0 \n", + "151870 0.0 0.0 0.0 0.0 \n", + "151871 0.0 0.0 0.0 0.0 \n", + "151872 0.0 0.0 0.0 0.0 \n", + "151873 0.0 0.0 0.0 0.0 \n", + "\n", + " vente_internet_max purchase_date_min purchase_date_max \\\n", + "0 0.0 550.000000 550.000000 \n", + "1 0.0 550.000000 550.000000 \n", + "2 0.0 508.227674 508.227674 \n", + "3 0.0 550.000000 550.000000 \n", + "4 0.0 550.000000 550.000000 \n", + "... ... ... ... \n", + "151869 0.0 550.000000 550.000000 \n", + "151870 0.0 550.000000 550.000000 \n", + "151871 0.0 550.000000 550.000000 \n", + "151872 0.0 550.000000 550.000000 \n", + "151873 0.0 550.000000 550.000000 \n", + "\n", + " time_between_purchase nb_tickets_internet fidelity ... \\\n", + "0 -1.0 0.0 2 ... \n", + "1 -1.0 0.0 1 ... \n", + "2 0.0 0.0 4 ... \n", + "3 -1.0 0.0 0 ... \n", + "4 -1.0 0.0 0 ... \n", + "... ... ... ... ... \n", + "151869 -1.0 0.0 0 ... \n", + "151870 -1.0 0.0 0 ... \n", + "151871 -1.0 0.0 1 ... \n", + "151872 -1.0 0.0 0 ... \n", + "151873 -1.0 0.0 0 ... \n", + "\n", + " gender_female gender_male gender_other nb_campaigns \\\n", + "0 1 0 0 2.0 \n", + "1 1 0 0 2.0 \n", + "2 1 0 0 12.0 \n", + "3 0 0 1 10.0 \n", + "4 1 0 0 1.0 \n", + "... ... ... ... ... \n", + "151869 0 0 1 1.0 \n", + "151870 0 1 0 8.0 \n", + "151871 1 0 0 14.0 \n", + "151872 0 1 0 16.0 \n", + "151873 0 1 0 11.0 \n", + "\n", + " nb_campaigns_opened has_purchased has_purchased_estim score \\\n", + "0 0.0 0.0 0.0 0.425710 \n", + "1 1.0 0.0 0.0 0.442888 \n", + "2 5.0 0.0 0.0 0.293107 \n", + "3 0.0 0.0 0.0 0.062345 \n", + "4 0.0 0.0 0.0 0.421351 \n", + "... ... ... ... ... \n", + "151869 1.0 0.0 0.0 0.258200 \n", + "151870 4.0 0.0 1.0 0.538124 \n", + "151871 4.0 0.0 1.0 0.548488 \n", + "151872 3.0 0.0 0.0 0.179400 \n", + "151873 8.0 0.0 0.0 0.220966 \n", + "\n", + " quartile score_adjusted \n", + "0 2 0.068441 \n", + "1 2 0.073036 \n", + "2 2 0.039474 \n", + "3 1 0.006547 \n", + "4 2 0.067312 \n", + "... ... ... \n", + "151869 2 0.033348 \n", + "151870 3 0.103520 \n", + "151871 3 0.107461 \n", + "151872 1 0.021208 \n", + "151873 1 0.027343 \n", + "\n", + "[151874 rows x 22 columns]" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_segment(X_test, y_test, logit_cv)" + ] + }, { "cell_type": "markdown", "id": "ad16b8ab-7e01-404b-971e-866e9b9d5aa4", @@ -1579,7 +2056,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 17, "id": "f0379536-a6c5-4b16-bde5-d0319ec1b140", "metadata": {}, "outputs": [], @@ -1592,7 +2069,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 18, "id": "32a0dfd0-f49d-4785-a56f-706d381bfe41", "metadata": {}, "outputs": [], @@ -1608,7 +2085,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 19, "id": "2dff1def-02df-413e-afce-b4aeaf7752b6", "metadata": {}, "outputs": [], @@ -1619,7 +2096,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 20, "id": "683d71fc-7442-4028-869c-49c57592d6e9", "metadata": {}, "outputs": [], @@ -1642,17 +2119,17 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 38, "id": "781b0d40-c954-4c54-830a-e709c8667328", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "6.172331113516847" + "10.140994712235674" ] }, - "execution_count": 32, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" } @@ -1668,17 +2145,17 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 39, "id": "248cb862-418e-4767-9933-70c4885ecf40", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "6.070461139075353" + "10.089625954992135" ] }, - "execution_count": 33, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -1695,7 +2172,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 40, "id": "fff6cbe6-7bb3-4732-9b81-b9ac5383bbcf", "metadata": {}, "outputs": [ @@ -1703,7 +2180,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "betâ test - betâ train = 0.016642008368292337\n" + "betâ test - betâ train = 0.005078328390017222\n" ] } ], @@ -1713,7 +2190,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 41, "id": "f506870d-4a8a-4b2c-8f0b-e0789080b20c", "metadata": {}, "outputs": [ @@ -1721,7 +2198,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "mean absolute erreur 0.001409799678121875\n" + "mean absolute erreur 0.00033179180098895215\n" ] } ], @@ -1736,7 +2213,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 42, "id": "8213d0e4-063b-49fa-90b7-677fc34f4c01", "metadata": {}, "outputs": [ @@ -1744,7 +2221,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/tmp/ipykernel_521/1825363704.py:7: SettingWithCopyWarning: \n", + "/tmp/ipykernel_1080/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", @@ -1765,7 +2242,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 43, "id": "834d3723-2e72-4c65-9c62-e2d595c69461", "metadata": {}, "outputs": [ @@ -1773,10 +2250,10 @@ "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" + "MSE for score : 0.16848909203423532\n", + "MSE for ajusted score : 0.06481787838756012\n", + "sum of y_has_purchased : 13300.0\n", + "sum of adjusted scores : 13350.390547983186\n" ] } ], @@ -1794,7 +2271,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 44, "id": "9f30a4dd-a9d8-405a-a7d5-5324ae88cf70", "metadata": {}, "outputs": [ @@ -1802,8 +2279,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "MAE for score : 0.32116357895490416\n", - "MAE for adjusted score : 0.17359227315595824\n" + "MAE for score : 0.3534914169353957\n", + "MAE for adjusted score : 0.13026115637615288\n" ] } ], @@ -1818,7 +2295,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 28, "id": "6f9396db-e213-408c-a596-eaeec3bc79f3", "metadata": {}, "outputs": [], @@ -1862,13 +2339,13 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 45, "id": "b478d40d-9677-4204-87bd-16fb0bc1fe9a", "metadata": {}, "outputs": [ { "data": { - "image/png": "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8fHxMDQ0RL169aCvr1+WuSkOn/NWAJ/zRkRECqC057yVauQtn4mJCd55552yyoWIiIiIXqFUNywQERERUeVg8UZERESkICzeiIiIiBSExRsRERGRgrB4IyIiIlIQFm9ERERECvJajwqht8+JhAdltqwd286X2bIKM6e3W7kun4iI6E3EkTciIiIiBWHxRkRERKQgLN6IiIiIFITFGxEREZGCsHgjIiIiUhAWb0REREQKwuKNiIiISEFYvBEREREpCIs3IiIiIgVh8UZERESkICzeiIiIiBSExRsRERGRgrB4IyIiIlIQFm9ERERECsLijYiIiEhBWLwRERERKQiLNyIiIiIFYfFGREREpCAs3oiIiIgUhMUbERERkYKweCMiIiJSEBZvRERERArC4o2IiIhIQVi8ERERESkIizciIiIiBWHxRkRERKQgLN6IiIiIFITFGxEREZGCsHgjIiIiUhAWb0REREQKwuKNiIiISEFYvBEREREpCIs3IiIiIgVh8UZERESkICzeiIiIiBSExRsRERGRgrB4IyIiIlIQFm9EREREClKpxducOXPwzjvvwNTUFDY2NujVqxcuX74sixFCYPr06bC3t4ehoSHatm2LixcvymKysrIwevRoWFlZwdjYGD169MDt27dlMampqQgICIBarYZarUZAQADS0tJkMbdu3UL37t1hbGwMKysrBAcHIzs7u1y2nYiIiKg0KrV4i4qKwsiRI3H8+HFERkbi2bNn8PHxQWZmphQzb948LFq0CMuXL0dMTAzs7OzQqVMnPHz4UIoJCQnB9u3bERYWhiNHjuDRo0fw8/NDbm6uFOPv74+4uDiEh4cjPDwccXFxCAgIkKbn5uaiW7duyMzMxJEjRxAWFoatW7ciNDS0YjqDiIiIqBhUQghR2Unku3fvHmxsbBAVFYU2bdpACAF7e3uEhIRg0qRJAJ6Pstna2mLu3LkYNmwY0tPTYW1tjQ0bNuDDDz8EANy5cwcODg7Ys2cPfH19ER8fDxcXFxw/fhweHh4AgOPHj8PT0xN//vknnJycsHfvXvj5+SExMRH29vYAgLCwMAwYMAApKSkwMzN7Zf4ZGRlQq9VIT08vVnyJ7BpTtst7iRMJD8psWTuqTyyzZRVmTm+3cl0+ERH9O5Tr8bscvFHXvKWnpwMALCwsAAAJCQlITk6Gj4+PFKOvrw9v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", + "image/png": "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58+fx8mTJ9G3b18AQGxsLBISEuDs7CzNo62tDScnJ4SGhgIAoqKikJmZKYtRqVSws7OTYsLCwqBUKqWiEAA6duwIpVIpi7Gzs5OKQgBwcXFBeno6oqKiityG9PR0pKamyl5ERERE1ZFGVSdQnGnTpiElJQVNmzaFuro6srOz8d///heffPIJACAhIQEAYGZmJpvPzMwMt2/flmK0tLRgaGhYICZv/oSEBJiamhZYv6mpqSwm/3oMDQ2hpaUlxRQmICAAc+bMKc1mExEREVWJat1juG3bNmzevBlbt27F2bNnsXHjRixevBgbN26UxSkUCtmwEKLAuPzyxxQWX5aY/GbMmIGUlBTpFRcXV2xeRERERFWlWvcYTpkyBdOnT8fHH38MALC3t8ft27cREBCAoUOHwtzcHMCL3jwLCwtpvsTERKl3z9zcHBkZGUhKSpL1GiYmJqJTp05SzP379wus/8GDB7LlREREyKYnJSUhMzOzQE/iv2lra0NbW7ssm09ERERUqap1j+GzZ8+gpiZPUV1dXXpcTcOGDWFubo6QkBBpekZGBo4dOyYVfW3btoWmpqYsJj4+HpcuXZJiHBwckJKSgtOnT0sxERERSElJkcVcunQJ8fHxUkxwcDC0tbXRtm3bct5yIiIiospXrXsM3dzc8N///hf169dH8+bNce7cOSxduhTDhw8H8OLUrq+vL+bPn4/GjRujcePGmD9/PvT09ODu7g4AUCqVGDFiBPz8/GBkZIS6deti8uTJsLe3R8+ePQEAzZo1Q+/eveHl5YXvv/8eADBy5Ei4urrCxsYGAODs7AxbW1t4eHhg0aJFePToESZPngwvL6/X+u4kIiIienNU68Jw5cqVmDVrFry9vZGYmAiVSoVRo0bhyy+/lGKmTp2KtLQ0eHt7IykpCR06dEBwcDBq164txSxbtgwaGhoYNGgQ0tLS0KNHD2zYsAHq6upSzJYtW+Dj4yPdvdy/f3+sWrVKmq6uro59+/bB29sbjo6O0NXVhbu7OxYvXlwJLUFERERU8ar1cwxfR3yOYT58jiEREdUAfI4hEREREb1RWBgSEREREQAWhkRERESUi4UhEREREQFgYUhEREREuVgYEhEREREAFoZERERElIuFIREREREBYGFIRERERLlYGBIRERERABaGRERERJSLhSERERERAWBhSERERES5WBgS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d3csXry4graeiIiIqHLVqOcYvg74HEO5iNhHVZ1Cqe2uN7WqUyi1mvicOj7HsPLUxP2DqLLxOYZERERE9EZhYUhEREREAFgYEhEREVEuFoZEREREBICFIRERERHlYmFIRERERABYGBIRERFRLhaGRERERASAhSERERER5WJhSEREREQAWBgSERERUS4WhkREREQEgIUhEREREeXSqOoEiKjizdh5sapTICKiGoA9hkREREQEgIUhEREREeViYUhEREREAFgYEhEREVEuFoZEREREBICFIRERERHlYmFIRERERABYGBIRERFRLhaGRERERASAhSERERER5WJhSEREREQAWBgSERERUS4WhkREREQEgIUhEREREeXSqOoEqPxExD6q6hSIiIioBmOPIREREREBYGFIRERERLlYGBIRERERABaGRERERJSLN58QEVGNM2PnxapOodQCPrCv6hSIXoqFIVEpDbi7sKpTKLXd9aZWdQpERFQD8FQyEREREQFgYUhEREREuXgqmYjoDVcTr9cjoorBwpCIiKgS1MQCnDfMvHl4KpmIiIiIALAwJCIiIqJcLAyJiIiICACvMSQiIqIi8LrINw8LQ6I3AB/KTUREJcFTyUREREQEgIUhEREREeViYUhEREREAFgYEhEREVEu3nxSBt999x0WLVqE+Ph4NG/eHMuXL0fnzp2rOi2i10pNvGGmpuKNPkSUhz2GpbRt2zb4+vpi5syZOHfuHDp37ow+ffrgzp07VZ0aERER0SthYVhKS5cuxYgRI/D555+jWbNmWL58OaysrLB69eqqTo2IiIjolfBUcilkZGQgKioK06dPl413dnZGaGhoFWVFRPRqeNq+ctTEU/Y1c9/YVNUJ1GgsDEvhn3/+QXZ2NszMzGTjzczMkJCQUOg86enpSE9Pl4ZTUlIAAKmpqeWe39PnGeW+TCIiKh+9/pxX1SmU2tOqTqAMKuL79d/LFUJUyPKrCxaGZaBQKGTDQogC4/IEBARgzpw5BcZbWVlVSG5ERERvtGnbK3Txjx8/hlKprNB1VCUWhqVgbGwMdXX1Ar2DiYmJBXoR88yYMQOTJk2ShnNycvDo0SMYGRkVWUyWRWpqKqysrBAXFwcDA4NyWy7JsZ0rB9u58rCtKwfbuXJUZDsLIfD48WOoVKpyXW51w8KwFLS0tNC2bVuEhITg/fff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1xd//PEHYmNjcfbsWRw+fFj6Q2Ds2LF49OgRPvnkE5w+fRp//fUXgoODMXz48EL/ECF6U7EwJKrmhgwZgrS0NLRv3x5jx47F+PHjMXLkyGLnadOmDbZv347AwEDY2dnhyy+/xNy5cwvcTevn54eoqCi0bt0aX331FZYsWQIXFxcAQKtWrbB06VIsWLAAdnZ22LJlCwICAgqsS09PD9OmTYO7uzscHBygq6uLwMDAMm/v3LlzcevWLbz11lswMTGRTRsxYgQyMjIwfPjwly7n66+/xocffggPDw+0adMGf/75J/744w8YGhqWOBcTExNs2LABv/zyC2xtbfH1119j8eLFpd4mAFiyZAmsrKzQpUsXuLu7Y/LkydDT05Oma2hoYMWKFfj++++hUqnw3nvvAQCGDx+OoUOHYsiQIXByckLDhg3RrVu3l66vRYsWOHbsGG7cuIHOnTujdevWmDVrFiwsLIqd7+2338YHH3yAvn37wtnZGXZ2dvjuu++k6WXNp0mTJggODsb58+fRvn17ODg44LfffoOGRskep1uS/TE7Oxtjx45Fs2bN0Lt3b9jY2Ei5q1QqnDp1CtnZ2XBxcYGdnR0mTJgApVIJNTV+FRLlUYiSXnhERJWua9euaNWqVaX9Ekh1t2XLFkyYMAH37t3jA5MrgL+/P3bv3s1fXyF6g/GXT4io2nv27BliY2MREBCAUaNGsSgkIqog7D8nompv4cKFaNWqFczMzDBjxoyqToeI6LXFU8lEREREBIA9hkRERESUi4UhEREREQFgYUhEREREuVgYEhEREREAFoZERERElIuFIREREREBYGFIRERERLlYGBIRERERABaGRERERJTr/wC61vLbQFJeSQAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -1936,9 +2413,841 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 46, "id": "90c4c2b5-0ede-4001-889f-749cfbd9df04", "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
quartilescore (%)score adjusted (%)has purchased (%)
0114.621.702.04
1239.166.225.24
2358.1112.6412.57
3486.0943.1245.98
\n", + "
" + ], + "text/plain": [ + " quartile score (%) score adjusted (%) has purchased (%)\n", + "0 1 14.62 1.70 2.04\n", + "1 2 39.16 6.22 5.24\n", + "2 3 58.11 12.64 12.57\n", + "3 4 86.09 43.12 45.98" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X_test_table_adjusted_scores = (100 * X_test_segment.groupby(\"quartile\")[[\"score\",\"score_adjusted\", \"has_purchased\"]].mean()).round(2).reset_index()\n", + "X_test_table_adjusted_scores = X_test_table_adjusted_scores.rename(columns = {col : f\"{col.replace('_', ' ')} (%)\" for col in X_test_table_adjusted_scores.columns if col in [\"score\",\"score_adjusted\", \"has_purchased\"]})\n", + "X_test_table_adjusted_scores" + ] + }, + { + "cell_type": "code", + "execution_count": 162, + "id": "d0b8740c-cf48-4a3e-83cb-23d95059f62f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'\\\\begin{tabular}{lrrr}\\n\\\\toprule\\nquartile & score (%) & score adjusted (%) & has purchased (%) \\\\\\\\\\n\\\\midrule\\n1 & 13.250000 & 2.510000 & 1.570000 \\\\\\\\\\n2 & 33.890000 & 8.000000 & 9.850000 \\\\\\\\\\n3 & 63.060000 & 22.580000 & 21.470000 \\\\\\\\\\n4 & 90.520000 & 66.200000 & 65.010000 \\\\\\\\\\n\\\\bottomrule\\n\\\\end{tabular}\\n'" + ] + }, + "execution_count": 162, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X_test_table_adjusted_scores.to_latex(index=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "d6a04d3e-c454-43e4-ae4c-0746e928575b", + "metadata": {}, + "outputs": [], + "source": [ + "# comparison between score and adjusted score - export csv associated\n", + "\n", + "file_name = \"table_adjusted_score_\"\n", + "FILE_PATH_OUT_S3 = PATH + file_name + type_of_activity + \".csv\"\n", + "with fs.open(FILE_PATH_OUT_S3, 'w') as file_out:\n", + " X_test_table_adjusted_scores.to_csv(file_out, index = False)" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "a974589f-7952-4db2-bebf-7b69c6b09372", + "metadata": {}, + "outputs": [], + "source": [ + "def project_tickets_CA (df, nb_purchases, 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.loc[:,\"nb_tickets_projected\"] = df_output.loc[:,nb_tickets] / duration_ratio\n", + " df_output.loc[:,\"total_amount_projected\"] = df_output.loc[:,total_amount] / duration_ratio\n", + " \n", + " df_output.loc[:,\"nb_tickets_expected\"] = df_output.loc[:,score_adjusted] * df_output.loc[:,\"nb_tickets_projected\"]\n", + " df_output.loc[:,\"total_amount_expected\"] = df_output.loc[:,score_adjusted] * df_output.loc[:,\"total_amount_projected\"]\n", + "\n", + " df_output.loc[:,\"pace_purchase\"] = (duration_ref/df_output.loc[:,nb_purchases]).apply(lambda x : np.nan if x==np.inf else x)\n", + " \n", + " return df_output\n" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "id": "dd8a52e1-d06e-4790-8687-8e58e3e6b84e", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_1080/3982240549.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.loc[:,\"nb_tickets_projected\"] = df_output.loc[:,nb_tickets] / duration_ratio\n", + "/tmp/ipykernel_1080/3982240549.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.loc[:,\"total_amount_projected\"] = df_output.loc[:,total_amount] / duration_ratio\n", + "/tmp/ipykernel_1080/3982240549.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.loc[:,\"nb_tickets_expected\"] = df_output.loc[:,score_adjusted] * df_output.loc[:,\"nb_tickets_projected\"]\n", + "/tmp/ipykernel_1080/3982240549.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.loc[:,\"total_amount_expected\"] = df_output.loc[:,score_adjusted] * df_output.loc[:,\"total_amount_projected\"]\n", + "/tmp/ipykernel_1080/3982240549.py:13: 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.loc[:,\"pace_purchase\"] = (duration_ref/df_output.loc[:,nb_purchases]).apply(lambda x : np.nan if x==np.inf else x)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nb_ticketsnb_purchasestotal_amountnb_suppliersvente_internet_maxpurchase_date_minpurchase_date_maxtime_between_purchasenb_tickets_internetfidelity...has_purchasedhas_purchased_estimscorequartilescore_adjustednb_tickets_projectedtotal_amount_projectednb_tickets_expectedtotal_amount_expectedpace_purchase
00.00.00.00.00.0550.000000550.000000-1.00.02...0.00.00.42571020.0684410.0000000.0000000.0000000.00000NaN
10.00.00.00.00.0550.000000550.000000-1.00.01...0.00.00.44288820.0730360.0000000.0000000.0000000.00000NaN
24.01.040.01.00.0508.227674508.2276740.00.04...0.00.00.29310720.0394742.82352928.2352940.1114551.1145517.0
30.00.00.00.00.0550.000000550.000000-1.00.00...0.00.00.06234510.0065470.0000000.0000000.0000000.00000NaN
40.00.00.00.00.0550.000000550.000000-1.00.00...0.00.00.42135120.0673120.0000000.0000000.0000000.00000NaN
..................................................................
1518690.00.00.00.00.0550.000000550.000000-1.00.00...0.00.00.25820020.0333480.0000000.0000000.0000000.00000NaN
1518700.00.00.00.00.0550.000000550.000000-1.00.00...0.01.00.53812430.1035200.0000000.0000000.0000000.00000NaN
1518710.00.00.00.00.0550.000000550.000000-1.00.01...0.01.00.54848830.1074610.0000000.0000000.0000000.00000NaN
1518720.00.00.00.00.0550.000000550.000000-1.00.00...0.00.00.17940010.0212080.0000000.0000000.0000000.00000NaN
1518730.00.00.00.00.0550.000000550.000000-1.00.00...0.00.00.22096610.0273430.0000000.0000000.0000000.00000NaN
\n", + "

151874 rows × 27 columns

\n", + "
" + ], + "text/plain": [ + " nb_tickets nb_purchases total_amount nb_suppliers \\\n", + "0 0.0 0.0 0.0 0.0 \n", + "1 0.0 0.0 0.0 0.0 \n", + "2 4.0 1.0 40.0 1.0 \n", + "3 0.0 0.0 0.0 0.0 \n", + "4 0.0 0.0 0.0 0.0 \n", + "... ... ... ... ... \n", + "151869 0.0 0.0 0.0 0.0 \n", + "151870 0.0 0.0 0.0 0.0 \n", + "151871 0.0 0.0 0.0 0.0 \n", + "151872 0.0 0.0 0.0 0.0 \n", + "151873 0.0 0.0 0.0 0.0 \n", + "\n", + " vente_internet_max purchase_date_min purchase_date_max \\\n", + "0 0.0 550.000000 550.000000 \n", + "1 0.0 550.000000 550.000000 \n", + "2 0.0 508.227674 508.227674 \n", + "3 0.0 550.000000 550.000000 \n", + "4 0.0 550.000000 550.000000 \n", + "... ... ... ... \n", + "151869 0.0 550.000000 550.000000 \n", + "151870 0.0 550.000000 550.000000 \n", + "151871 0.0 550.000000 550.000000 \n", + "151872 0.0 550.000000 550.000000 \n", + "151873 0.0 550.000000 550.000000 \n", + "\n", + " time_between_purchase nb_tickets_internet fidelity ... \\\n", + "0 -1.0 0.0 2 ... \n", + "1 -1.0 0.0 1 ... \n", + "2 0.0 0.0 4 ... \n", + "3 -1.0 0.0 0 ... \n", + "4 -1.0 0.0 0 ... \n", + "... ... ... ... ... \n", + "151869 -1.0 0.0 0 ... \n", + "151870 -1.0 0.0 0 ... \n", + "151871 -1.0 0.0 1 ... \n", + "151872 -1.0 0.0 0 ... \n", + "151873 -1.0 0.0 0 ... \n", + "\n", + " has_purchased has_purchased_estim score quartile \\\n", + "0 0.0 0.0 0.425710 2 \n", + "1 0.0 0.0 0.442888 2 \n", + "2 0.0 0.0 0.293107 2 \n", + "3 0.0 0.0 0.062345 1 \n", + "4 0.0 0.0 0.421351 2 \n", + "... ... ... ... ... \n", + "151869 0.0 0.0 0.258200 2 \n", + "151870 0.0 1.0 0.538124 3 \n", + "151871 0.0 1.0 0.548488 3 \n", + "151872 0.0 0.0 0.179400 1 \n", + "151873 0.0 0.0 0.220966 1 \n", + "\n", + " score_adjusted nb_tickets_projected total_amount_projected \\\n", + "0 0.068441 0.000000 0.000000 \n", + "1 0.073036 0.000000 0.000000 \n", + "2 0.039474 2.823529 28.235294 \n", + "3 0.006547 0.000000 0.000000 \n", + "4 0.067312 0.000000 0.000000 \n", + "... ... ... ... \n", + "151869 0.033348 0.000000 0.000000 \n", + "151870 0.103520 0.000000 0.000000 \n", + "151871 0.107461 0.000000 0.000000 \n", + "151872 0.021208 0.000000 0.000000 \n", + "151873 0.027343 0.000000 0.000000 \n", + "\n", + " nb_tickets_expected total_amount_expected pace_purchase \n", + "0 0.000000 0.00000 NaN \n", + "1 0.000000 0.00000 NaN \n", + "2 0.111455 1.11455 17.0 \n", + "3 0.000000 0.00000 NaN \n", + "4 0.000000 0.00000 NaN \n", + "... ... ... ... \n", + "151869 0.000000 0.00000 NaN \n", + "151870 0.000000 0.00000 NaN \n", + "151871 0.000000 0.00000 NaN \n", + "151872 0.000000 0.00000 NaN \n", + "151873 0.000000 0.00000 NaN \n", + "\n", + "[151874 rows x 27 columns]" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X_test_segment = project_tickets_CA (X_test_segment, \"nb_purchases\", \"nb_tickets\", \"total_amount\", \"score_adjusted\", \n", + " duration_ref=17, duration_projection=12)\n", + "X_test_segment" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "id": "cb66a8ea-65f7-460f-b3fc-ba76a3b91faa", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "quartile\n", + "1 16.475616\n", + "2 16.474062\n", + "3 15.707271\n", + "4 11.484654\n", + "Name: pace_purchase, dtype: float64" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X_test_segment.groupby(\"quartile\")[\"pace_purchase\"].mean()" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "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, pace_purchase,\n", + " duration_ref=1.5, duration_projection=1) :\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_ratio=duration_ref/duration_projection\n", + " \n", + " df_expected_CA[\"revenue_recovered_perct\"] = 100 * duration_ratio * df_expected_CA[total_amount_expected] / \\\n", + " df.groupby(segment)[total_amount].sum().values\n", + "\n", + " df_drop_null_pace = df.dropna(subset=[pace_purchase])\n", + " df_expected_CA[\"pace_purchase\"] = df_drop_null_pace.groupby(segment)[pace_purchase].mean().values\n", + " \n", + " return df_expected_CA" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "c8df6c80-43e8-4f00-9cd3-eb9022744313", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
quartilesizesize_perctnb_tickets_expectedtotal_amount_expectedrevenue_recovered_perctpace_purchase
015362635.31398.2613949.332.3516.48
125597436.863113.77101639.456.2416.47
233043520.046214.35208267.2214.2715.71
34118397.8072929.461835702.4375.3811.48
\n", + "
" + ], + "text/plain": [ + " quartile size size_perct nb_tickets_expected total_amount_expected \\\n", + "0 1 53626 35.31 398.26 13949.33 \n", + "1 2 55974 36.86 3113.77 101639.45 \n", + "2 3 30435 20.04 6214.35 208267.22 \n", + "3 4 11839 7.80 72929.46 1835702.43 \n", + "\n", + " revenue_recovered_perct pace_purchase \n", + "0 2.35 16.48 \n", + "1 6.24 16.47 \n", + "2 14.27 15.71 \n", + "3 75.38 11.48 " + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X_test_expected_CA = round(summary_expected_CA(df=X_test_segment, segment=\"quartile\", \n", + " nb_tickets_expected=\"nb_tickets_expected\", total_amount_expected=\"total_amount_expected\", \n", + " total_amount=\"total_amount\", pace_purchase=\"pace_purchase\"),2)\n", + "\n", + "X_test_expected_CA" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "id": "ac706ed7-defa-4df1-82e1-06f12fc1b6ad", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'\\\\begin{tabular}{lrrrrrr}\\n\\\\toprule\\nquartile & size & size (%) & nb tickets expected & total amount expected & revenue recovered (%) & pace purchase \\\\\\\\\\n\\\\midrule\\n1 & 53626 & 35.310000 & 398.260000 & 13949.330000 & 2.350000 & 16.480000 \\\\\\\\\\n2 & 55974 & 36.860000 & 3113.770000 & 101639.450000 & 6.240000 & 16.470000 \\\\\\\\\\n3 & 30435 & 20.040000 & 6214.350000 & 208267.220000 & 14.270000 & 15.710000 \\\\\\\\\\n4 & 11839 & 7.800000 & 72929.460000 & 1835702.430000 & 75.380000 & 11.480000 \\\\\\\\\\n\\\\bottomrule\\n\\\\end{tabular}\\n'" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Création du dictionnaire de mapping pour les noms de colonnes\n", + "mapping_dict = {col: col.replace(\"perct\", \"(%)\").replace(\"_\", \" \") for col in X_test_expected_CA.columns}\n", + "\n", + "X_test_expected_CA.rename(columns=mapping_dict).to_latex(index=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "id": "771da0cf-c49f-4e7e-b52f-ebcfb0fb2df3", + "metadata": {}, + "outputs": [], + "source": [ + "# export summary table to the MinIO storage\n", + "\n", + "file_name = \"table_expected_CA_\"\n", + "FILE_PATH_OUT_S3 = PATH + file_name + type_of_activity + \".csv\"\n", + "with fs.open(FILE_PATH_OUT_S3, 'w') as file_out:\n", + " X_test_expected_CA.to_csv(file_out, index = False)" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "c805dc10-4d07-4f7d-a677-5461a92845d7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'projet-bdc2324-team1/Output_expected_CA/musique/table_expected_CA_musique.csv'" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "PATH = f\"projet-bdc2324-team1/Output_expected_CA/{type_of_activity}/\"\n", + "file_name = \"table_expected_CA_\"\n", + "FILE_PATH_OUT_S3 = PATH + file_name + type_of_activity + \".csv\"\n", + "FILE_PATH_OUT_S3" + ] + }, + { + "cell_type": "markdown", + "id": "e35ccfff-1845-41f0-9bde-f09b09b67877", + "metadata": {}, + "source": [ + "## Test : vizu tables saved" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "id": "4e9e88e4-ea10-41f4-9bf1-20b55269a20d", + "metadata": {}, "outputs": [ { "data": { @@ -2001,701 +3310,24 @@ "" ], "text/plain": [ - " quartile score (%) score adjusted (%) has purchased (%)\n", - "0 1 13.25 2.51 1.57\n", - "1 2 33.89 8.00 9.85\n", - "2 3 63.06 22.58 21.47\n", - "3 4 90.52 66.20 65.01" + " quartile score (%) score adjusted (%) has purchased (%)\n", + "0 1 13.25 2.51 1.57\n", + "1 2 33.89 8.00 9.85\n", + "2 3 63.06 22.58 21.47\n", + "3 4 90.52 66.20 65.01" ] }, - "execution_count": 42, + "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "X_test_table_adjusted_scores = (100 * X_test_segment.groupby(\"quartile\")[[\"score\",\"score_adjusted\", \"has_purchased\"]].mean()).round(2).reset_index()\n", - "X_test_table_adjusted_scores = X_test_table_adjusted_scores.rename(columns = {col : f\"{col.replace('_', ' ')} (%)\" for col in X_test_table_adjusted_scores.columns if col in [\"score\",\"score_adjusted\", \"has_purchased\"]})\n", - "X_test_table_adjusted_scores" - ] - }, - { - "cell_type": "code", - "execution_count": 162, - "id": "d0b8740c-cf48-4a3e-83cb-23d95059f62f", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'\\\\begin{tabular}{lrrr}\\n\\\\toprule\\nquartile & score (%) & score adjusted (%) & has purchased (%) \\\\\\\\\\n\\\\midrule\\n1 & 13.250000 & 2.510000 & 1.570000 \\\\\\\\\\n2 & 33.890000 & 8.000000 & 9.850000 \\\\\\\\\\n3 & 63.060000 & 22.580000 & 21.470000 \\\\\\\\\\n4 & 90.520000 & 66.200000 & 65.010000 \\\\\\\\\\n\\\\bottomrule\\n\\\\end{tabular}\\n'" - ] - }, - "execution_count": 162, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "X_test_table_adjusted_scores.to_latex(index=False)" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "id": "d6a04d3e-c454-43e4-ae4c-0746e928575b", - "metadata": {}, - "outputs": [], - "source": [ - "# comparison between score and adjusted score - export csv associated\n", + "path = 'projet-bdc2324-team1/Output_expected_CA/sport/table_adjusted_scoresport.csv'\n", "\n", - "file_name = \"table_adjusted_score_\"\n", - "FILE_PATH_OUT_S3 = PATH + file_name + type_of_activity + \".csv\"\n", - "with fs.open(FILE_PATH_OUT_S3, 'w') as file_out:\n", - " X_test_table_adjusted_scores.to_csv(file_out, index = False)" - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "id": "a974589f-7952-4db2-bebf-7b69c6b09372", - "metadata": {}, - "outputs": [], - "source": [ - "def project_tickets_CA (df, nb_purchases, 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.loc[:,\"nb_tickets_projected\"] = df_output.loc[:,nb_tickets] / duration_ratio\n", - " df_output.loc[:,\"total_amount_projected\"] = df_output.loc[:,total_amount] / duration_ratio\n", - " \n", - " df_output.loc[:,\"nb_tickets_expected\"] = df_output.loc[:,score_adjusted] * df_output.loc[:,\"nb_tickets_projected\"]\n", - " df_output.loc[:,\"total_amount_expected\"] = df_output.loc[:,score_adjusted] * df_output.loc[:,\"total_amount_projected\"]\n", - "\n", - " df_output.loc[:,\"pace_purchase\"] = (duration_ref/df_output.loc[:,nb_purchases]).apply(lambda x : np.nan if x==np.inf else x)\n", - " \n", - " return df_output\n" - ] - }, - { - "cell_type": "code", - "execution_count": 79, - "id": "dd8a52e1-d06e-4790-8687-8e58e3e6b84e", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nb_ticketsnb_purchasestotal_amountnb_suppliersvente_internet_maxpurchase_date_minpurchase_date_maxtime_between_purchasenb_tickets_internetfidelity...has_purchasedhas_purchased_estimscorequartilescore_adjustednb_tickets_projectedtotal_amount_projectednb_tickets_expectedtotal_amount_expectedpace_purchase
04.01.0100.001.00.05.1771875.1771870.0000000.01...0.01.00.65767130.2403972.82352970.5882350.67876816.96920517.0
11.01.055.001.00.0426.265613426.2656130.0000000.02...1.00.00.26653820.0564820.70588238.8235290.0398702.19283017.0
217.01.080.001.00.0436.033437436.0334370.0000000.02...0.00.00.21466810.04308912.00000056.4705880.5170652.43324917.0
34.01.0120.001.00.05.1964125.1964120.0000000.01...0.01.00.65777030.2404782.82352984.7058820.67899520.36986117.0
434.02.0416.001.00.0478.693148115.631470363.0616780.04...1.01.00.89417340.58192024.000000293.64705913.966076170.8790528.5
..................................................................
960911.01.067.311.01.0278.442257278.4422570.0000001.02...1.01.00.62355130.2143690.70588247.5129410.15132010.18531817.0
960921.01.061.411.01.0189.207373189.2073730.0000001.01...0.01.00.68252130.2615260.70588243.3482350.18460711.33670117.0
960930.00.00.000.00.0550.000000550.000000-1.0000000.01...0.00.00.11719210.0214000.0000000.0000000.0000000.000000NaN
960941.01.079.431.01.0279.312905279.3129050.0000001.01...0.01.00.62518530.2155450.70588256.0682350.15215012.08524217.0
960950.00.00.000.00.0550.000000550.000000-1.0000000.02...0.00.00.31958520.0718170.0000000.0000000.0000000.000000NaN
\n", - "

96096 rows × 27 columns

\n", - "
" - ], - "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", - " has_purchased has_purchased_estim score quartile score_adjusted \\\n", - "0 0.0 1.0 0.657671 3 0.240397 \n", - "1 1.0 0.0 0.266538 2 0.056482 \n", - "2 0.0 0.0 0.214668 1 0.043089 \n", - "3 0.0 1.0 0.657770 3 0.240478 \n", - "4 1.0 1.0 0.894173 4 0.581920 \n", - "... ... ... ... ... ... \n", - "96091 1.0 1.0 0.623551 3 0.214369 \n", - "96092 0.0 1.0 0.682521 3 0.261526 \n", - "96093 0.0 0.0 0.117192 1 0.021400 \n", - "96094 0.0 1.0 0.625185 3 0.215545 \n", - "96095 0.0 0.0 0.319585 2 0.071817 \n", - "\n", - " nb_tickets_projected total_amount_projected nb_tickets_expected \\\n", - "0 2.823529 70.588235 0.678768 \n", - "1 0.705882 38.823529 0.039870 \n", - "2 12.000000 56.470588 0.517065 \n", - "3 2.823529 84.705882 0.678995 \n", - "4 24.000000 293.647059 13.966076 \n", - "... ... ... ... \n", - "96091 0.705882 47.512941 0.151320 \n", - "96092 0.705882 43.348235 0.184607 \n", - "96093 0.000000 0.000000 0.000000 \n", - "96094 0.705882 56.068235 0.152150 \n", - "96095 0.000000 0.000000 0.000000 \n", - "\n", - " total_amount_expected pace_purchase \n", - "0 16.969205 17.0 \n", - "1 2.192830 17.0 \n", - "2 2.433249 17.0 \n", - "3 20.369861 17.0 \n", - "4 170.879052 8.5 \n", - "... ... ... \n", - "96091 10.185318 17.0 \n", - "96092 11.336701 17.0 \n", - "96093 0.000000 NaN \n", - "96094 12.085242 17.0 \n", - "96095 0.000000 NaN \n", - "\n", - "[96096 rows x 27 columns]" - ] - }, - "execution_count": 79, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "X_test_segment = project_tickets_CA (X_test_segment, \"nb_purchases\", \"nb_tickets\", \"total_amount\", \"score_adjusted\", \n", - " duration_ref=17, duration_projection=12)\n", - "X_test_segment" - ] - }, - { - "cell_type": "code", - "execution_count": 82, - "id": "cb66a8ea-65f7-460f-b3fc-ba76a3b91faa", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "quartile\n", - "1 16.581057\n", - "2 15.840818\n", - "3 14.888091\n", - "4 4.830480\n", - "Name: pace_purchase, dtype: float64" - ] - }, - "execution_count": 82, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "X_test_segment.groupby(\"quartile\")[\"pace_purchase\"].mean()" - ] - }, - { - "cell_type": "code", - "execution_count": 118, - "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, pace_purchase,\n", - " duration_ref=1.5, duration_projection=1) :\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_ratio=duration_ref/duration_projection\n", - " \n", - " df_expected_CA[\"revenue_recovered_perct\"] = 100 * duration_ratio * df_expected_CA[total_amount_expected] / \\\n", - " df.groupby(segment)[total_amount].sum().values\n", - "\n", - " df_drop_null_pace = df.dropna(subset=[pace_purchase])\n", - " df_expected_CA[\"pace_purchase\"] = df_drop_null_pace.groupby(segment)[pace_purchase].mean().values\n", - " \n", - " return df_expected_CA" - ] - }, - { - "cell_type": "code", - "execution_count": 119, - "id": "c8df6c80-43e8-4f00-9cd3-eb9022744313", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
quartilesizesize_perctnb_tickets_expectedtotal_amount_expectedrevenue_recovered_perctpace_purchase
013741038.9389.751977.024.6416.58
122951730.723069.8378841.0810.4315.84
232013720.9611516.60364538.8224.1914.89
3490329.40227853.3510481736.5195.414.83
\n", - "
" - ], - "text/plain": [ - " quartile size size_perct nb_tickets_expected total_amount_expected \\\n", - "0 1 37410 38.93 89.75 1977.02 \n", - "1 2 29517 30.72 3069.83 78841.08 \n", - "2 3 20137 20.96 11516.60 364538.82 \n", - "3 4 9032 9.40 227853.35 10481736.51 \n", - "\n", - " revenue_recovered_perct pace_purchase \n", - "0 4.64 16.58 \n", - "1 10.43 15.84 \n", - "2 24.19 14.89 \n", - "3 95.41 4.83 " - ] - }, - "execution_count": 119, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "X_test_expected_CA = round(summary_expected_CA(df=X_test_segment, segment=\"quartile\", \n", - " nb_tickets_expected=\"nb_tickets_expected\", total_amount_expected=\"total_amount_expected\", \n", - " total_amount=\"total_amount\", pace_purchase=\"pace_purchase\"),2)\n", - "\n", - "X_test_expected_CA" - ] - }, - { - "cell_type": "code", - "execution_count": 120, - "id": "ac706ed7-defa-4df1-82e1-06f12fc1b6ad", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'\\\\begin{tabular}{lrrrrrr}\\n\\\\toprule\\nquartile & size & size (%) & nb tickets expected & total amount expected & revenue recovered (%) & pace purchase \\\\\\\\\\n\\\\midrule\\n1 & 37410 & 38.930000 & 89.750000 & 1977.020000 & 4.640000 & 16.580000 \\\\\\\\\\n2 & 29517 & 30.720000 & 3069.830000 & 78841.080000 & 10.430000 & 15.840000 \\\\\\\\\\n3 & 20137 & 20.960000 & 11516.600000 & 364538.820000 & 24.190000 & 14.890000 \\\\\\\\\\n4 & 9032 & 9.400000 & 227853.350000 & 10481736.510000 & 95.410000 & 4.830000 \\\\\\\\\\n\\\\bottomrule\\n\\\\end{tabular}\\n'" - ] - }, - "execution_count": 120, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Création du dictionnaire de mapping pour les noms de colonnes\n", - "mapping_dict = {col: col.replace(\"perct\", \"(%)\").replace(\"_\", \" \") for col in X_test_expected_CA.columns}\n", - "\n", - "X_test_expected_CA.rename(columns=mapping_dict).to_latex(index=False)" - ] - }, - { - "cell_type": "code", - "execution_count": 122, - "id": "771da0cf-c49f-4e7e-b52f-ebcfb0fb2df3", - "metadata": {}, - "outputs": [], - "source": [ - "# export summary table to the MinIO storage\n", - "\n", - "file_name = \"table_expected_CA_\"\n", - "FILE_PATH_OUT_S3 = PATH + file_name + type_of_activity + \".csv\"\n", - "with fs.open(FILE_PATH_OUT_S3, 'w') as file_out:\n", - " X_test_expected_CA.to_csv(file_out, index = False)" + "with fs.open( path, mode=\"rb\") as file_in:\n", + " df = pd.read_csv(file_in, sep=\",\")\n", + "df" ] }, { diff --git a/utils_CA_segment.py b/utils_CA_segment.py index 6794bf9..4e20816 100644 --- a/utils_CA_segment.py +++ b/utils_CA_segment.py @@ -1,3 +1,83 @@ +# importations +import pandas as pd +from pandas import DataFrame +import numpy as np +import os +import s3fs +import matplotlib.pyplot as plt +from scipy.optimize import fsolve +import pickle +import warnings +import io + +# functions + +def load_train_test(type_of_activity): + BUCKET = f"projet-bdc2324-team1/Generalization/{type_of_activity}" + File_path_train = BUCKET + "/Train_set.csv" + File_path_test = BUCKET + "/Test_set.csv" + + with fs.open( File_path_train, mode="rb") as file_in: + dataset_train = pd.read_csv(file_in, sep=",") + # dataset_train['y_has_purchased'] = dataset_train['y_has_purchased'].fillna(0) + + with fs.open(File_path_test, mode="rb") as file_in: + dataset_test = pd.read_csv(file_in, sep=",") + # dataset_test['y_has_purchased'] = dataset_test['y_has_purchased'].fillna(0) + + return dataset_train, dataset_test + + +def features_target_split(dataset_train, dataset_test): + + features_l = ['nb_tickets', 'nb_purchases', 'total_amount', 'nb_suppliers', 'vente_internet_max', 'purchase_date_min', 'purchase_date_max', + 'time_between_purchase', 'nb_tickets_internet', 'fidelity', 'is_email_true', 'opt_in', #'is_partner', + 'gender_female', 'gender_male', 'gender_other', 'nb_campaigns', 'nb_campaigns_opened'] + + # we suppress fidelity, time between purchase, and gender other (colinearity issue) + """ + features_l = ['nb_tickets', 'nb_purchases', 'total_amount', 'nb_suppliers', 'vente_internet_max', + 'purchase_date_min', 'purchase_date_max', 'nb_tickets_internet', 'is_email_true', + 'opt_in', 'gender_female', 'gender_male', 'nb_campaigns', 'nb_campaigns_opened'] + """ + + X_train = dataset_train[features_l] + y_train = dataset_train[['y_has_purchased']] + + X_test = dataset_test[features_l] + y_test = dataset_test[['y_has_purchased']] + + return X_train, X_test, y_train, y_test + + +def load_model(type_of_activity, model): + BUCKET = f"projet-bdc2324-team1/Output_model/{type_of_activity}/{model}/" + filename = model + '.pkl' + file_path = BUCKET + filename + with fs.open(file_path, mode="rb") as f: + model_bytes = f.read() + + model = pickle.loads(model_bytes) + return model + + +def df_segment(df, y, model) : + + y_pred = model.predict(df) + y_pred_prob = model.predict_proba(df)[:, 1] + + df_segment = df + + df_segment["has_purchased"] = y + df_segment["has_purchased_estim"] = y_pred + df_segment["score"] = y_pred_prob + df_segment["quartile"] = np.where(df_segment['score']<0.25, '1', + np.where(df_segment['score']<0.5, '2', + np.where(df_segment['score']<0.75, '3', '4'))) + + return df_segment + + def odd_ratio(score) : """ Args: @@ -152,3 +232,14 @@ def summary_expected_CA(df, segment, nb_tickets_expected, total_amount_expected, df_expected_CA["pace_purchase"] = df_drop_null_pace.groupby(segment)[pace_purchase].mean().values return df_expected_CA + + +def save_file_s3_ca(File_name, type_of_activity): + image_buffer = io.BytesIO() + plt.savefig(image_buffer, format='png') + image_buffer.seek(0) + PATH = f"projet-bdc2324-team1/Output_expected_CA/{type_of_activity}/" + FILE_PATH_OUT_S3 = PATH + File_name + type_of_activity + '.png' + with fs.open(FILE_PATH_OUT_S3, 'wb') as s3_file: + s3_file.write(image_buffer.read()) + plt.close()