205 lines
7.6 KiB
Python
205 lines
7.6 KiB
Python
### importations ###
|
|
|
|
import pandas as pd
|
|
import numpy as np
|
|
import os
|
|
import io
|
|
import s3fs
|
|
import re
|
|
import pickle
|
|
import warnings
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
|
### functions for segmentation and graphics associated ###
|
|
|
|
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 load_test_file(type_of_activity):
|
|
file_path_test = f"projet-bdc2324-team1/Generalization/{type_of_activity}/Test_set.csv"
|
|
with fs.open(file_path_test, mode="rb") as file_in:
|
|
dataset_test = pd.read_csv(file_in, sep=",")
|
|
return dataset_test
|
|
|
|
|
|
def save_file_s3_mp(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_marketing_personae_analysis/{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()
|
|
|
|
|
|
def df_business_fig(df, segment, list_var) :
|
|
df_business_kpi = df.groupby(segment)[list_var].sum().reset_index()
|
|
df_business_kpi.insert(1, "size", df.groupby(segment).size().values)
|
|
all_var = ["size"] + list_var
|
|
df_business_kpi[all_var] = 100 * df_business_kpi[all_var] / df_business_kpi[all_var].sum()
|
|
|
|
return df_business_kpi
|
|
|
|
|
|
def hist_segment_business_KPIs(df, segment, size, nb_tickets, nb_purchases, total_amount, nb_campaigns) :
|
|
|
|
plt.figure()
|
|
|
|
df_plot = df[[segment, size, nb_tickets, nb_purchases, total_amount, nb_campaigns]]
|
|
|
|
x = ["number of\ncustomers", "number of\ntickets", "number of\npurchases", "total\namount",
|
|
"number of\ncampaigns"]
|
|
|
|
bottom = np.zeros(5)
|
|
|
|
# types of blue color
|
|
colors = plt.cm.Blues(np.linspace(0.1, 0.9, 4))
|
|
|
|
for i in range(4) :
|
|
height = list(df_plot.loc[i,size:].values)
|
|
plt.bar(x=x, height=height, label = str(df_plot[segment][i]), bottom=bottom, color=colors[i])
|
|
bottom+=height
|
|
|
|
# Ajust margins
|
|
plt.subplots_adjust(left = 0.125, right = 0.8, bottom = 0.1, top = 0.9)
|
|
|
|
plt.legend(title = "segment", loc = "upper right", bbox_to_anchor=(1.2, 1))
|
|
plt.ylabel("Fraction represented by the segment (%)")
|
|
plt.title("Relative weight of each segment regarding business KPIs")
|
|
# plt.show()
|
|
|
|
|
|
def df_segment_mp(df, segment, gender_female, gender_male, gender_other, country_fr) :
|
|
df_mp = df.groupby(segment)[[gender_female, gender_male, gender_other, country_fr]].mean().reset_index()
|
|
df_mp.insert(3, "share_known_gender", X_test_segment_mp[gender_female]+X_test_segment_mp[gender_male])
|
|
df_mp.insert(4, "share_of_women", X_test_segment_mp[gender_female]/(X_test_segment_mp["share_known_gender"]))
|
|
return df_mp
|
|
|
|
|
|
def df_segment_pb (df, segment, nb_tickets_internet, nb_tickets, nb_campaigns_opened, nb_campaigns, opt_in) :
|
|
df_used = df
|
|
df_used["share_tickets_internet"] = df_used[nb_tickets_internet]/df_used[nb_tickets]
|
|
df_used["share_campaigns_opened"] = df_used[nb_campaigns_opened]/df_used[nb_campaigns]
|
|
df_pb = df_used.groupby(segment)[["share_tickets_internet", "share_campaigns_opened", opt_in]].mean().reset_index()
|
|
return df_pb
|
|
|
|
|
|
def radar_mp_plot(df, categories, index) :
|
|
categories = categories
|
|
|
|
# true values are used to print the true value in parenthesis
|
|
tvalues = list(df.loc[index,categories])
|
|
|
|
max_values = df[categories].max()
|
|
|
|
# values are true values / max among the 4 segments, allows to
|
|
# put values in relation with the values for other segments
|
|
# if the point has a maximal abscisse it means that value is maximal for the segment considered
|
|
# , event if not equal to 1
|
|
|
|
values = list(df.loc[index,categories]/max_values)
|
|
|
|
# values normalized are used to adjust the value around the circle
|
|
# for instance if the maximum of values is equal to 0.8, we want the point to be
|
|
# at 8/10th of the circle radius, not at the edge
|
|
values_normalized = [ max(values) * elt for elt in values]
|
|
|
|
# Nb of categories
|
|
num_categories = len(categories)
|
|
|
|
angles = np.linspace(0, 2 * np.pi, num_categories, endpoint=False).tolist()
|
|
|
|
# Initialize graphic
|
|
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(polar=True))
|
|
|
|
# we have to draw first a transparent line (alpha=0) of values to adjust the radius of the circle
|
|
# which is based on max(value)
|
|
ax.plot(angles + angles[:1], values + values[:1], color='skyblue', alpha=0, linewidth=1.5)
|
|
ax.plot(angles + angles[:1], values_normalized + values_normalized[:1], color='black', alpha = 0.5, linewidth=1.2)
|
|
|
|
# fill the sector
|
|
ax.fill(angles, values_normalized, color='orange', alpha=0.4)
|
|
|
|
# labels
|
|
ax.set_yticklabels([])
|
|
ax.set_xticks(angles)
|
|
ticks = [categories[i].replace("_"," ") + f"\n({round(100 * tvalues[i],2)}%)" for i in range(len(categories))]
|
|
ax.set_xticklabels(ticks, color="black")
|
|
|
|
ax.spines['polar'].set_visible(False)
|
|
|
|
plt.title(f'Characteristics of the segment {index+1}\n')
|
|
|
|
# plt.show()
|
|
|
|
|
|
def radar_mp_plot_all(df, categories) :
|
|
|
|
nb_segments = df.shape[0]
|
|
categories = categories
|
|
|
|
# Initialize graphic
|
|
fig, ax = plt.subplots(2,2, figsize=(25, 20), subplot_kw=dict(polar=True))
|
|
|
|
for index in range(nb_segments) :
|
|
row = index // 2 # Division entière pour obtenir le numéro de ligne
|
|
col = index % 2
|
|
|
|
df = X_test_segment_caract
|
|
|
|
# true values are used to print the true value in parenthesis
|
|
tvalues = list(df.loc[index,categories])
|
|
|
|
max_values = df[categories].max()
|
|
|
|
# values are true values / max among the 4 segments, allows to
|
|
# put values in relation with the values for other segments
|
|
# if the point has a maximal abscisse it means that value is maximal for the segment considered
|
|
# , event if not equal to 1
|
|
|
|
values = list(df.loc[index,categories]/max_values)
|
|
|
|
# values normalized are used to adjust the value around the circle
|
|
# for instance if the maximum of values is equal to 0.8, we want the point to be
|
|
# at 8/10th of the circle radius, not at the edge
|
|
values_normalized = [ max(values) * elt for elt in values]
|
|
|
|
# Nb of categories
|
|
num_categories = len(categories)
|
|
|
|
angles = np.linspace(0, 2 * np.pi, num_categories, endpoint=False).tolist()
|
|
|
|
# we have to draw first a transparent line (alpha=0) of values to adjust the radius of the circle
|
|
# which is based on max(value)
|
|
ax[row, col].plot(angles + angles[:1], values + values[:1], color='skyblue', alpha=0, linewidth=1.5)
|
|
ax[row, col].plot(angles + angles[:1], values_normalized + values_normalized[:1], color='black', alpha = 0.5,
|
|
linewidth=1.2)
|
|
|
|
# fill the sector
|
|
ax[row, col].fill(angles, values_normalized, color='orange', alpha=0.4, label = index)
|
|
|
|
# labels
|
|
ax[row, col].set_yticklabels([])
|
|
ax[row, col].set_xticks(angles)
|
|
ticks = [categories[i].replace("_"," ") + f"\n({round(100 * tvalues[i],2)}%)" for i in range(len(categories))]
|
|
ax[row, col].set_xticklabels(ticks, color="black", size = 20)
|
|
|
|
ax[row, col].spines['polar'].set_visible(False)
|
|
|
|
ax[row, col].set_title(f'Characteristics of the segment {index+1}\n', size = 24)
|
|
|
|
# plt.show()
|
|
|
|
|
|
|