<jupyter_start><jupyter_text>[3. Machine Learning](section3) &emsp; [3.1. Cas d’étude](section3.1) &emsp; [3.2. Industrialisation du processus de prédiction](section3.2) &emsp; [3.3. Analyse focalisée](section3.3) &emsp; [3.4. Prédiction](section3.4) [4. Synthèse](section4) &emsp; [4.1. Conclusion (SWOT)](section4.1) &emsp; [4.2. Bilan](section4.2)   Modélisation de modèle d'apprentissage automatique, comparaisons avec des modèles ensembliste   1. Préparation des données pour l'analyse / Preparing the data for analysisSource : - [Estimation de la population INSEE](https://www.insee.fr/fr/statistiques/1893198)([Document source](https://www.insee.fr/fr/statistiques/fichier/1893198/estim-pop-dep-sexe-gca-1975-2020.xls))- [Crimes et délits enregistrés en France](https://www.data.gouv.fr/fr/datasets/chiffres-departementaux-mensuels-relatifs-aux-crimes-et-delits-enregistres-par-les-services-de-police-et-de-gendarmerie-depuis-janvier-1996/)([Document source](https://www.data.gouv.fr/fr/datasets/r/fdf5afbf-ed3c-4c54-a4f0-3581c8a1eca4)) *1.1. Importation des outils / Tools import*<jupyter_code>import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(color_codes=True)
# Transformation de base

### Generique variables definition to import
source = 'source/'
xl_misdemeanours_crimes_path = source + 'tableaux-4001-ts.xlsx'
xl_population_path = source + 'estim-pop-dep-sexe-gca-1975-2020.xls'

### Excel file import
crime_xl_data = pd.ExcelFile(xl_misdemeanours_crimes_path)
population_xl_data = pd.ExcelFile(xl_population_path)

# Define France metropolitaine
current_sheet = crime_xl_data.sheet_names[1]

# Read one sheet to begin ('Fra<nce_Métro') --> libellée index to write minus two lines
df = pd.read_excel(crime_xl_data, current_sheet, index_col = 'libellé index')

# Drop init 'index' columns, and Transpose Data
df = df.drop(columns=['Index'])
df = df.T

df_all = pd.DataFrame(columns=df.columns.values)
df_all['departement'] = np.nan

all_name_sheet = crime_xl_data.sheet_names
invalid_sheet = ['France_Entière','France_Métro']
all_name_sheet = [e for e in all_name_sheet if e not in invalid_sheet]

for i in all_name_sheet:
    df_tmp = pd.read_excel(crime_xl_data, sheet_name=str(i), index_col = 'libellé index')
    df_tmp = df_tmp.drop(columns=['Index'])
    df_tmp = df_tmp.T
    df_tmp['departement'] = str(i)
    df_all = df_all.append(df_tmp) 
    
df_all.departement = df_all.departement.astype(str)

# Sur le jeu de donnée France métropolitaine
# Reset index, Get Year, Get Month
df = df.reset_index()
df['year'] = df['index'].astype(str).str[0:4]
df['month'] = df['index'].astype(str).str[5:7]

# Define new date column
combined = df.year.str.cat(df.month,sep=' ')
df['date'] = pd.to_datetime(combined)

# Drop 'index' column and set new index on date
df = df.drop(columns='index')
df = df.set_index('date')

# Sur le jeu de donnée complet
# Reset index, Get Year, Get Month
df_all = df_all.reset_index()
df_all['year'] = df_all['index'].astype(str).str[0:4]
df_all['month'] = df_all['index'].astype(str).str[5:7]

# Define new date column
combined = df_all.year.str.cat(df_all.month,sep=' ')
df_all['date'] = pd.to_datetime(combined)

# Drop 'index' column and set new index on date
df_all = df_all.drop(columns='index')
df_all = df_all.set_index('date')

df.year = df.year.astype(str).astype(int)
df.month = df.month.astype(str)


# Define names of index and columns
df.index.names = ['index']
df.columns.names = ['libellé columns']

df_all = df_all.drop(columns='Index non utilisé')
df = df.drop(columns='Index non utilisé')<jupyter_output><empty_output><jupyter_text>2. Analyse macro du jeu de données / Macro data analyseIntéressons-nous au jeu de données du point de vue macro.<jupyter_code># Chargement de XL en Dataframe
df_population = pd.read_excel(population_xl_data, '2020', header = 4, index='Départements')
# Nettoyage du jeu de données
df_population.rename(columns={'Unnamed: 0':'Departement','Total.1':'Total Homme','Total.2':'Total Femme'}, inplace=True)

# Suppresion des lignes indésirables
df_population = df_population.drop([96, 102, 103, 104, 105])

valid_population_columns = ['Departement', 'Total','Total Homme','Total Femme']

# Finition sur le DataFrame
df_population = df_population[valid_population_columns]
df_population.head()
# Vision globale
plt.matshow(df.corr())
plt.show()
column_to_analyse = df_all.columns.values

# Enlever le département dans les colones à analyse
# Delete num departement
column_to_analyse = np.delete(column_to_analyse,-3)
# delete month
column_to_analyse = np.delete(column_to_analyse,-1)
# delte year
column_to_sum = np.delete(column_to_analyse,-1)


df_france=df.loc[:,column_to_sum]
df_france["Total Incident"] = df_france[column_to_sum].sum(axis=1)
df_france = df_france.drop(columns=column_to_sum)
df_france.head(5)

fig, ax = plt.subplots(figsize = (10, 6))
sns.lineplot(data=df_france, ax=ax, ci=int, linewidth=1);
column_to_analyse = df_all.columns.values

# Enlever le département dans les colones à analyse
# Delete num departement
column_to_analyse = np.delete(column_to_analyse,-3)
# delete month
column_to_analyse = np.delete(column_to_analyse,-1)

# Validation du typage dans ce df
df_all[column_to_analyse] = df_all[column_to_analyse].astype(int)
df_all.departement = df_all.departement.astype(str)
df_all['total_incidents'] = df_all[column_to_analyse].sum(axis=1)
df_all.head()<jupyter_output><empty_output><jupyter_text>Le jeu de donnée est maintenant utilisable. Regardons une description du nombre de crime et délit commis par département.<jupyter_code>df_all.groupby('departement').total_incidents.describe().head()
mean = round((df_all.groupby('departement').total_incidents.mean().values).mean(),2)
print("Moyenne : " + str(mean))
print("Moyenne x 3 : " + str(mean*3))
print("Moyenne / 3 : " + str(mean/3))<jupyter_output>Moyenne : 4933.76
Moyenne x 3 : 14801.28
Moyenne / 3 : 1644.5866666666668<jupyter_text>Depuis 1996, nous pouvons constater qu'en France par département et par mois, il y a en moyenne 4945 incidents.Les limites supérieures à notre analyse vont être égales à 3 fois plus et 3 fois moins la valeur moyenne. Elles correspondent ainsi à 14 835 (limite haute) et 1 648 (limite basse) d'incidents.<jupyter_code>moyenne = round(df_all.groupby('departement').total_incidents.mean(), 2).values
departement = df_all.groupby('departement').total_incidents.mean().keys()

df_mean_departement = pd.DataFrame({'Moyenne':moyenne})
df_mean_departement = df_mean_departement.set_index(departement)

print("Moyenne d'acte criminel/délit par mois par département")

df_mean_departement = df_mean_departement.sort_values(by='Moyenne', ascending=True)
print(df_mean_departement.head())
df_mean_departement = df_mean_departement.sort_values(by='Moyenne', ascending=False)
print(df_mean_departement.head())
print("Departement avec nb incidents supérieur à la limite haute : ")
print(df_mean_departement[df_mean_departement['Moyenne'] > (mean*3)])
print("Departement avec nb incidents inférieur à la limite basse : ")
print(df_mean_departement[df_mean_departement['Moyenne'] < (mean/3)].values)

# Nombre d'incidents total en fm sur l'année 2019
year = df_all.groupby('year').total_incidents.sum()
print("\nNombre d'incidents sur l'année 2019 : " + str(year[2019]))

# Nombre d'incidents total par département sur l'année 2019
year = df_all.groupby(['year','departement']).total_incidents.sum()
year[2019].head()<jupyter_output>Departement avec nb incidents supérieur à la limite haute : 
              Moyenne
departement          
75           24377.22
13           16227.19
59           16144.00
Departement avec nb incidents inférieur à la limite basse : 
[]

Nombre d'incidents sur l'année 2019 : 6428563<jupyter_text>Au vu du nombre d'incidents constaté, nous pouvons supposé que les 3 départements 75, 13 et 59 peuvent être assimilé à des zones plus à risques car avec un nombre d'incidents supérieur à la limite du nombre d'incidents préétabli. Mais pour avoir une vision plus réalisée, regardons le pourcentage d'incident par individu (à savoir par habitant) en fonction des départements.<jupyter_code>df_tmp = df_population.merge(year[2019], left_on='Departement', right_on='departement')
df_tmp.head()
df_tmp["% Incident / Personne"] = round(df_tmp["total_incidents"] / df_tmp["Total"] * 100, 2)
df_tmp.head()
df_tmp = df_tmp.sort_values(by='% Incident / Personne', ascending=True)
df_tmp.head(10)
df_tmp = df_tmp.sort_values(by='% Incident / Personne', ascending=False)
df_tmp.head(10)
cambriolage_columns = df.filter(regex=(".*[Cc]ambriolage?s.*")).columns.values<jupyter_output><empty_output><jupyter_text>3. Machine Learning Reprenons le jeu de donnée initial. Nous allons opérer en trois temps :- Réalisation d’un premier modèle « simpliste » avec deux modèles sur un cas d’usage- Mise en place d’un processus de prédiction « industriel » sur de multiples variables- Évaluation des résultats des modèles d’apprentissage 3.1. Cas d’étude : prédiction des cambriolages en France par département et par moisCommençons par importer les librairies nécessaires à ce premier point<jupyter_code>import numpy as np
import pandas as pd

from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import train_test_split

from sklearn.metrics import accuracy_score, mean_squared_error, mean_squared_log_error

from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor<jupyter_output><empty_output><jupyter_text>Ensuite, définissons les variables nécessaires à notre cas d’étude. Elles vont permettre de préparer les données d’entré des différents modèles et de réaliser par la suite un train test split. Nous allons aussi réaliser une étape de prétransformation (ici une seule de catégorisation). L’objectif par cette étape est de considérer toutes les valeurs possibles des différentes dimensions d’input comme étant elle-même des dimensions.<jupyter_code>########################################
# Define input & array columns
input_columns = ['departement','year','month']
array_input_columns = np.asarray(input_columns)

########################################
# Case to study
cambriolage_columns = df.filter(regex=(".*[Cc]ambriolage?s.*")).columns.values
champs_to_predict = "Total_Cambriolage"
column_to_use = np.concatenate((cambriolage_columns, array_input_columns), axis=None)

##################################################
# Préparation des données d'input
df_ml = df_all.loc[:,column_to_use]
df_ml[champs_to_predict] = df_ml[cambriolage_columns].sum(axis=1)
df_ml = df_ml.drop(columns=cambriolage_columns)
df_ml = df_ml['2018':'2019']
df_ml = df_ml.reset_index()

values_to_drop = [champs_to_predict,'date']
X = df_ml.drop(labels = values_to_drop, axis=1)
y = df_ml.loc[:,champs_to_predict]

##################################################
#  No pipeline, only pre_processor categorical
enc = OneHotEncoder()
enc.fit(X)
X = enc.transform(X).toarray()

#########################
# Train & Test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
y_test = pd.Series(y_test, dtype='float')<jupyter_output>RMSE test 1 : 61.17491029666858
% Err Moy effectif test 1 : 18.5 %
RMSE test 2 : 57.9396550633558
% Err Moy effectif test 2 : 47.9 %<jupyter_text>Les données sont prêtes à être exploitées par des modèles d’apprentissage. Dès l’obtention des prédictions, nous pourrons comparer les résultats sur ce modèle d’apprentissage. Pour calculer évaluer l’impact de se modèle, nous allons calculer deux variables : le RMSE et le pourcentage d’erreur moyen relatif aux données réelles. Pour ces deux mesures, l’objectif est d’avoir la plus petite valeur possible.<jupyter_code>##################################################
# Apprentissage
cart_ml = DecisionTreeRegressor()
reg_ml = LinearRegression()

cart_ml.fit(X_train, y_train)
reg_ml.fit(X_train, y_train)

#########################
# prediction
y_test_pred_1 = cart_ml.predict(X_test)
y_test_pred_2 = reg_ml.predict(X_test)

#########################
# Output Test
X_test = enc.inverse_transform(X_test)

# DTR
df_ml_res_test_1 = pd.DataFrame(
    data = X_test,
    columns = input_columns
)
df_ml_res_test_1["Valeur_Reel"] = y_test.values
df_ml_res_test_1["Valeur_Predict"] = y_test_pred_1
df_ml_res_test_1["Difference_abs"] = abs(df_ml_res_test_1["Valeur_Reel"]-df_ml_res_test_1["Valeur_Predict"])
df_ml_res_test_1["%_Error"] = df_ml_res_test_1["Difference_abs"]/df_ml_res_test_1["Valeur_Reel"]

# LR
df_ml_res_test_2 = pd.DataFrame(
    data = X_test,
    columns = input_columns
)
df_ml_res_test_2["Valeur_Reel"] = y_test.values
df_ml_res_test_2["Valeur_Predict"] = y_test_pred_2
df_ml_res_test_2["Difference_abs"] = abs(df_ml_res_test_2["Valeur_Reel"]-df_ml_res_test_2["Valeur_Predict"])
df_ml_res_test_2["%_Error"] = df_ml_res_test_2["Difference_abs"]/df_ml_res_test_2["Valeur_Reel"]

#########################
# Résultats
df_moy_1 = df_ml_res_test_1[df_ml_res_test_1["Valeur_Reel"] != 0]
Err_Moy_Test_1 = round(df_moy_1["%_Error"].mean(),3)*100

df_moy_2 = df_ml_res_test_2[df_ml_res_test_2["Valeur_Reel"] != 0]
Err_Moy_Test_2 = round(df_moy_2["%_Error"].mean(),3)*100

RMSE_test_1 = np.sqrt(mean_squared_error(y_test, y_test_pred_1))
RMSE_test_2 = np.sqrt(mean_squared_error(y_test, y_test_pred_2))

#########################
# Affichage

print("RMSE test 1 : " + str(RMSE_test_1))
print("% Err Moy effectif test 1 : " + str(Err_Moy_Test_1) + " %")
print("RMSE test 2 : " + str(RMSE_test_2))
print("% Err Moy effectif test 2 : " + str(Err_Moy_Test_2) + " %")<jupyter_output><empty_output><jupyter_text>En regardant ces résultats, nous pouvons tout de suite distinguer une grande disparité entre le RMSE et le pourcentage d’erreur moyen relatif. Si nous nous focalisons sur le RMSE, nous pouvons supposer que le test 2 est plus performant. À contrario, en se focalisant sur le pourcentage d’erreurs moyen effectif, ce serait le test 1.En effet, si les deux modèles étaient relativement égaux (en termes de performance et de variation), les deux RMSE et les pourcentages d’erreurs moyennes effectifs aurait été proches l’un de l’autre. Or, ici le pourcentage d’erreurs moyen effectif (que l’on pourrait nommer l’erreur « réel ») est bien inférieur pour le premier test.Cet aspect est totalement compréhensible. En effet, les modèles disposent en entrée d’une grande variété de valeurs (et par conséquent possiblement d’échelle). L’objectif est de minimiser l’erreur globale indépendamment des résultats. Pour pouvoir tenir compte au même poids des différences d’échelle, la mesure RMSE n’est pas la plus optimale et il faut privilégier le RMSLE.En réalité l’utilisation du RMSLE permet uniquement de minimiser les erreurs des données d’eu aux différentes échelles ainsi que celle outliers. Dans une comparaison entre deux modèles distincts, le RMSE peut être suffisant. Cependant, ici nous allons comparer potentiellement n modèle, avec n préprocesseur, dans n cas. Le RMSE va donc vite être limité !Remarque : avec le RMSLE il ne faut pas avoir de valeurs négatives et surtout n’avoir aucune valeur inférieure à 1. Compte tenu des potentiels résultats prédits, nous allons avoir deux manières de calculer le RMSLE : avec le log et le log + 1. Les résultats doivent théoriquement renvoyer le même résultat, sauf si une partie des données prédites se trouvent être entre – l’infinie et 0. Ainsi nous privilégierons le meilleur résultat parmi ces deux méthodes 😉<jupyter_code>ytest = y_test

ypred = y_test_pred_1
print("RMSLE 1 :")
print(np.sqrt(mean_squared_log_error(ypred, ytest)))
print(np.sqrt(mean_squared_log_error(np.abs(ypred), np.abs(ytest))))
print(np.sqrt(np.mean((np.log1p(ypred, out=None) - np.log1p(ytest, out=None))**2)))

print("RMSE 1 :")
print(np.sqrt(mean_squared_error(np.abs(ypred), np.abs(ytest))))

ypred = y_test_pred_2
print("RMSLE 2 :")
print(np.sqrt(mean_squared_log_error(np.abs(ypred), np.abs(ytest))))
print(np.sqrt(np.mean((np.log1p(ypred, out=None) - np.log1p(ytest, out=None))**2)))

print("RMSE 2 :")
print(np.sqrt(mean_squared_error(np.abs(ypred), np.abs(ytest))))<jupyter_output>RMSLE 1 :
0.24843909735763628
0.24843909735763628
0.2484390973576362
RMSE 1 :
61.17491029666858
RMSLE 2 :
0.5171634495426011
0.4099522135583395
RMSE 2 :
57.83806106017447<jupyter_text>Les résultats ici sont sans appel : le modèle du test 1 est bien plus performant que celui du test 2 et cela malgré à taux qui semblait être meilleur pour le RMSE. Nous pouvons aussi visualiser les tableaux associés aux résultats du test 1. Une seule chose à dire, c’est bien pour un premier jet.<jupyter_code>df_moy_1.head(6)
df_moy_2.head(6)<jupyter_output><empty_output><jupyter_text>3.2. Industrialisation du processus de prédictionMaintenant que la première partie est terminée et que les grandes étapes pour « ce modèle » ont été définies, nous pouvons mettre en place la base d’un processus de prédiction type « industriel ». Pour cela il va falloir « automatiser » toutes les « étapes » précédentes. Commençons d’abord par importer les modules nécessaires.<jupyter_code>from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, Normalizer, OneHotEncoder
from sklearn.model_selection import train_test_split

from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.svm import SVR

from joblib import dump, load<jupyter_output><empty_output><jupyter_text>Définissons ensuite les variables nécessaires à notre processus avec notamment :- Les variables nécessaires,- Les différents modèles devant être utilisés,- Le tableau des scores (qui servira à comparer les différents résultats de modèles),- Les dictionnaires qui vont récapituler les données utilisables dans le processus (équivalent à un mock)<jupyter_code>########################################
# Define input & array columns
input_columns = ['departement','year','month']
array_input_columns = np.asarray(input_columns)

########################################
# Define model regressor
cart_ml = DecisionTreeRegressor(criterion='mse')
rf_ml = RandomForestRegressor()
reg_ml = LinearRegression()
svr_ml = SVR()

models = [
    {
        'name':'cart',
        'model':cart_ml
    },
    {
        'name':'random forest',
        'model':rf_ml
    },
    {
        'name':'regression linéaire',
        'model':reg_ml
    },
    {
        'name':'SVR',
        'model':svr_ml
    }
]

########################################
# Préparation du tableau de score
columns = [
    'Dictionnaire',
    'ValeurPredict',
    'PreProcessing',
    'SCORING_Type',
    'Model',
    'SCORE_Test',
    'Err_Moy_Test',
    'SCORE_Val',
    'Err_Moy_Val'
]

data = {
    'Dictionnaire':["Nom du dictionnaire utilisé"],
    'ValeurPredict':["Nom de la variable"],
    'PreProcessing':["Pré-processus"],
    'SCORING_Type':['Nom du type de score'],
    'Model':["Nom du model"],
    'SCORE_Test':["0"],
    'Err_Moy_Test':["0"],
    'SCORE_Val':["0"],
    'Err_Moy_Val':["0"]
}

df_result = pd.DataFrame(data = data, columns = columns)
df_result = df_result.iloc[1:]

df_result['SCORE_Test'] = df_result['SCORE_Test'].astype(float)
df_result['Err_Moy_Test'] = df_result['Err_Moy_Test'].astype(float)
df_result['SCORE_Val'] = df_result['SCORE_Val'].astype(float)
df_result['Err_Moy_Val'] = df_result['Err_Moy_Val'].astype(float)

########################################
# Dictionnaire
####################
### Cambriolage
cambriolage_columns = df.filter(regex=(".*[Cc]ambriolage?s.*")).columns.values
other_cambriolage_columns = [
    'Cambriolages de résidences secondaires',
    'Cambriolages de locaux industriels, commerciaux ou financiers',
    "Cambriolages d'autres lieux"
]

# Dictionnaire
cambriolage_case = {
    'column_to_use':[
        np.concatenate((cambriolage_columns, array_input_columns), axis=None),
        np.concatenate(("Cambriolages de locaux d'habitations principales", array_input_columns), axis=None),
        np.concatenate((other_cambriolage_columns, array_input_columns), axis=None)
    ],
    'case':[cambriolage_columns,None,other_cambriolage_columns],
    'champs_to_predict':["Total_Cambriolage","Cambriolages de locaux d'habitations principales","Autre"],
    'date':('2018','2019'),
    'name':'cambriolage_case'
}

####################
# Homicide et tentative
# 2018 2019
# Homicide séparation
all_homicides_columns = df.filter(regex=(".*[Hh]omicide?s.*")).columns.values

only_homicides_columns = df.filter(regex=(".*Homicides.*")).columns.values
only_tentative_homicides_columns = df.filter(regex=(".*homicides.*")).columns.values

murder_case = {
    'column_to_use':[
        np.concatenate((only_homicides_columns, array_input_columns), axis=None),
        np.concatenate((only_tentative_homicides_columns, array_input_columns), axis=None)
    ],
    'case':[only_homicides_columns,only_tentative_homicides_columns],
    'champs_to_predict':["Total Homicide","Total tenta Homicide"],
    'date':('2018','2019'),
    'name':'murder_case'
}

####################
# les vols :
# Vols à main (3 cas) 2017 2019

vols_with_hands_column = df.filter(regex=(".*Vols à main.*")).columns.values
other_steal_columns = [
    'Vols à main armée contre des établissements financiers',
    'Vols à main armée contre des entreprises de transports de fonds',
    'Vols à main armée contre des particuliers à leur domicile'
]

theft_with_hand_case = {
    'column_to_use':[
        np.concatenate((vols_with_hands_column, array_input_columns), axis=None),
        np.concatenate(("Vols à main armée contre des éts industriels ou commerciaux", array_input_columns), axis=None),
        np.concatenate((other_steal_columns, array_input_columns), axis=None)
    ],
    'case':[vols_with_hands_column,None,other_steal_columns],
    'champs_to_predict':["Total vol main","Vols à main armée contre des éts industriels ou commerciaux","Autre Vol Main"],
    'date':('2018','2019'),
    'name':'theft_with_hand_case'
}

# Vols spécifique (3 cas) 2016 2019
vols_specific_column = ['Vols à la tire', "Vols à l'étalage", 'Vols à la roulotte']

specific_theft_case = {
    'column_to_use':[
        np.concatenate(('Vols à la tire', array_input_columns), axis=None),
        np.concatenate(("Vols à l'étalage", array_input_columns), axis=None),
        np.concatenate(('Vols à la roulotte', array_input_columns), axis=None)
    ],
    'case':[None,None,None],
    'champs_to_predict':['Vols à la tire',"Vols à l'étalage",'Vols à la roulotte'],
    'date':('2016','2019'),
    'name':'specific_theft_case'
}

# Vols violent (1 cas) 2018 2019
vols_violents_column = df.filter(regex=(".*Vols violents.*")).columns.values

violent_theft_case = {
    'column_to_use':[
        np.concatenate((vols_violents_column, array_input_columns), axis=None)
    ],
    'case':[vols_violents_column],
    'champs_to_predict':["Total vol violent"],
    'date':('2018','2019'),
    'name':'violent_theft_case'
}

# Vols simple
vols_simple_column = df.filter(regex=(".*simple.*")).columns.values

other_steal_2_columns = [
    'Vols simples sur chantier',
    'Vols simples sur exploitations agricoles',
    'Autres vols simples contre des établissements publics ou privés'
]

simple_theft_case = {
    'column_to_use':[
        np.concatenate((vols_simple_column, array_input_columns), axis=None),
        np.concatenate(('Autres vols simples contre des particuliers dans deslocaux privés', array_input_columns), axis=None),
        np.concatenate(('Autres vols simples contre des particuliers dans des locaux ou lieux publics', array_input_columns), axis=None),
        np.concatenate((other_steal_2_columns, array_input_columns), axis=None),
    ],
    'case':[vols_simple_column,None,None,other_steal_2_columns],
    'champs_to_predict':[
        "Total vol simple",
        'Autres vols simples contre des particuliers dans deslocaux privés',
        'Autres vols simples contre des particuliers dans des locaux ou lieux publics',
        'Autre vols simple'
    ],
    'date':('2016','2019'),
    'name':'simple_theft_case'
}<jupyter_output><empty_output><jupyter_text>Ensuite, fonctionnalisons tous points nécessaires aux traitements de ces données :- La préparation des données d’input- Le préprocesseur (l’optimisation et la réduction de code n’ont pas été prises en compte ici). Cette partie est l’une des plus modifiables, elle dépend à la fois des valeurs d’entrée et des modifications associées. - La prédiction des valeurs- L’évaluation des résultats avec la moyenne et le calcul du score en fonction du modèle- L’enregistrement du score- La modélisation d’un cas d’usage<jupyter_code># prepare data input
def df_prepare_data(df_input, column_to_use, case, champs, **kwargs):
    df = df_input.loc[:,column_to_use]
    if case is not None:
        df[champs] = df.loc[:,case].sum(axis=1)
        df = df.loc[:].drop(columns=case)
    if bool(kwargs.get('first')) or bool(kwargs.get('second')):
        df = df.loc[kwargs.get('first'):kwargs.get('seconde')]
    df = df.reset_index()
    return df

def modeling_pre_processor(**kwargs):
    preprocessor_case = kwargs.get('preprocessor_case')
    
    if preprocessor_case == 0:
        name = "SS year & OHE Dep, month"
        numeric_features = ['year']
        numeric_transformer = Pipeline(steps=[
            ('imputer', SimpleImputer(strategy='median')),
            ('scaler', StandardScaler())
        ])

        categorical_features = ['departement', 'month']
        categorical_transformer = Pipeline(steps=[
            ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
            ('onehot', OneHotEncoder(handle_unknown='ignore'))
        ])
        
        preprocessor = ColumnTransformer(
            transformers = [
                ('num', numeric_transformer, numeric_features),
                ('cat', categorical_transformer, categorical_features)
        ])
    
    elif preprocessor_case == 1:
        name = "N year & OHE Dep, month"
        
        numeric_features = ['year']
        numeric_transformer = Pipeline(steps=[
            ('imputer', SimpleImputer(strategy='median')),
            ('scaler', Normalizer())
        ])

        categorical_features = ['departement', 'month']
        categorical_transformer = Pipeline(steps=[
            ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
            ('onehot', OneHotEncoder(handle_unknown='ignore'))
        ])
        
        preprocessor = ColumnTransformer(
            transformers = [
                ('num', numeric_transformer, numeric_features),
                ('cat', categorical_transformer, categorical_features)
        ])
    
    elif preprocessor_case == 2:
        name = "OHE year, Dep, month"
        categorical_features = ['year','departement', 'month']
        categorical_transformer = Pipeline(steps=[
            ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
            ('onehot', OneHotEncoder(handle_unknown='ignore'))
        ])
        
        preprocessor = ColumnTransformer(
            transformers = [
                ('cat', categorical_transformer, categorical_features)
        ])

    return name, preprocessor


# Prediction resultats
def prediction_resultat(columns, X, Y_reel, Y_predict):
    df = pd.DataFrame(
        data = X,
        columns = columns
    )
    
    df["Valeur_Reel"] = Y_reel
    df["Valeur_Predict"] = Y_predict
    
    df["Difference_abs"] = abs(df["Valeur_Reel"]-df["Valeur_Predict"])
    df["%_Error"] = df["Difference_abs"]/df["Valeur_Reel"]
    
    return df

# recupère la moyenne
def get_mean(df, isNull=True):
    if isNull:
        df = df.loc[df["Valeur_Reel"] != 0]
        return df["%_Error"].mean()
    else:
        return df["%_Error"].mean()

# Methode de calculs des résultats RMSE
def score(ypred, ytest, score):
    assert len(ytest) == len(ypred)
    if score == "RMSLE_LOG1":
        return np.sqrt(np.mean((np.log1p(ypred, out=None) - np.log1p(ytest, out=None))**2))
    if score == "RMSLE":
        return np.sqrt(mean_squared_log_error(np.abs(ypred), np.abs(ytest)))

# RMSLE
# np.sqrt(mean_squared_log_error(np.abs(ypred), np.abs(ytest)))
# np.sqrt(np.mean((np.log1p(ypred, out=None) - np.log1p(ytest, out=None))**2))
# RMSE
# np.sqrt(mean_squared_error(np.abs(ypred), np.abs(ytest)))


# Enregistrement du score
def scoring(df, **kwargs):
    index = len(df.index)
    df.loc[index,'Dictionnaire'] = kwargs.get('Dictionnaire')
    df.loc[index,'ValeurPredict'] = kwargs.get('ValeurPredict')
    df.loc[index,'PreProcessing'] = kwargs.get('PreProcessing')
    df.loc[index,'Model'] = kwargs.get('Model')
    df.loc[index,'SCORING_Type'] = kwargs.get('SCORING_Type')
    df.loc[index,'SCORE_Test'] = kwargs.get('SCORE_Test')
    df.loc[index,'Err_Moy_Test'] = kwargs.get('Err_Moy_Test')
    df.loc[index,'SCORE_Val'] = kwargs.get('SCORE_Val')
    df.loc[index,'Err_Moy_Val'] = kwargs.get('Err_Moy_Val')
    return df

def run_dictionnary_case(df_main, df_result, dictionary_case, score_type, **kwargs):
    isDisplay = kwargs.get('isDisplay')
    if isDisplay:
        print("Start dictionary case " + dictionary_case['name'])
    
    for i in range(len(dictionary_case['column_to_use'])):
        if isDisplay:
            print("Case " + str(i+1) + "/" + str(len(dictionary_case['column_to_use'])) + " : " + dictionary_case['champs_to_predict'][i])

        champs_to_predict = dictionary_case['champs_to_predict'][i]

        ##################################################
        # Préparation des données d'input
        df_ml = df_prepare_data(
            df_input = df_main,
            column_to_use = dictionary_case['column_to_use'][i],
            champs = champs_to_predict,
            case = dictionary_case['case'][i],
            first = dictionary_case['date'][0],
            second = dictionary_case['date'][1]
        )

        values_to_drop = [champs_to_predict,'date']

        X = df_ml.drop(labels = values_to_drop, axis=1)
        y = df_ml[champs_to_predict]
        
        #########################
        # Train & Test
        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
        y_test = pd.Series(y_test, dtype='int32')
        
        #########################
        # Validation
        df_val = df_prepare_data(
            df_input = df_main[df_main['year'] == 2020],
            column_to_use = dictionary_case['column_to_use'][i],
            champs = champs_to_predict,
            case = dictionary_case['case'][i]
        )
        
        X_val = df_val.drop(labels = values_to_drop, axis=1)
        y_val = df_val[champs_to_predict]
        
        ##################################################
        # Modeling pre_processor pipeline
        pre_processor_name, preprocessor = modeling_pre_processor(
            preprocessor_case = kwargs.get('preprocessor_case')
        )
        
        ##################################################
        # Define current pipeline
        for model in models:
            model_processing = Pipeline(
                steps = [
                    ('preprocessor', preprocessor),
                    ('classifier', model['model'])
            ])
            model_processing.fit(X_train, y_train)
            
            #########################
            # Output modeling 
            filename = ''.join([
                'resultat/model/',
                dictionary_case['name'] + '_',
                champs_to_predict + '_',
                pre_processor_name + '_',
                model['name'] + '_',
                score_type + '_' + '.joblib'
            ])
            filename = filename.replace(" ", "_")
            dump(model_processing, filename) 
            
            #########################
            # Prédiction test
            y_test_pred = model_processing.predict(X_test)
            df_ml_res_test = prediction_resultat(
                columns = input_columns,
                X = X_test,
                Y_reel = y_test,
                Y_predict = y_test_pred
            )
            
            #########################
            # Prédiction val
            y_val_pred = model_processing.predict(X_val)
            df_ml_res_val = prediction_resultat(
                columns = input_columns,
                X = X_val,
                Y_reel = y_val,
                Y_predict = y_val_pred
            )
            
            #########################
            # Enregistrement
            score_test = score(y_test_pred, y_test, score=score_type)
            Err_Moy_Test = (get_mean(df_ml_res_test)*100)
            score_val = score(y_val_pred, y_val, score=score_type)
            Err_Moy_Val = (get_mean(df_ml_res_val)*100)
            
            #########################
            # Enregistrement du score
            df_result = scoring(
                df = df_result,
                Dictionnaire = dictionary_case['name'],
                ValeurPredict = champs_to_predict,
                PreProcessing = pre_processor_name,
                Model = model['name'],
                SCORING_Type = score_type,
                SCORE_Test = score_test,
                Err_Moy_Test = Err_Moy_Test,
                SCORE_Val = score_val,
                Err_Moy_Val = Err_Moy_Val
            )
            
            #########################
            # Affichage
            if isDisplay:
                print("Model : " + model['name'])
                print("\tScore test : " + str(score_test))
                print("\t% Err Moy test : " + str(round(Err_Moy_Test,3)) + " %")
                print("\tScore val : " + str(score_val))
                print("\t% Err Moy val : " + str(round(Err_Moy_Val,3)) + " %")
            
        if isDisplay:
            print("\n")<jupyter_output><empty_output><jupyter_text>Voici le code pour faire tourner la partie sur l’ensemble des modèles configurer dans le dictionnaire modèle. Exemple 1 :run_dictionnary_case(    df_main = df_all,    df_result = df_result,    dictionary_case = cambriolage_case,    preprocessor_case = 2,    score_type = "RMSLE",    isDisplay = True)Exemple 2 :run_dictionnary_case(    df_main = df_all,    df_result = df_result,    dictionary_case = cambriolage_case,    preprocessor_case = 2,    score_type = "RMSLE_LOG1",    isDisplay = False)Remarque : nous n’allons pas l’exécuter, car nous ne voulons de score en doublon.Remarque (2) : les modèles d’apprentissage choisi n’ont pas été configurés. En effet, ce travail sert de modèle d’évaluation et de prédiction sur le processus à suivre pour industrialiser une série de « champs à prédire ».Par ailleurs, les couches complémentaires telles que la paramétrisation (par défaut, simple, use case), l’ajout des modèles ensembliste (parallèle, séquentielle), l’ajustage des données d’input / pre-processing, le grid search (hypertuning) sont des possibilités, des étapes qui peuvent être réalisé et bien entendu ajouter à ce cas d’usage. Toutefois, à la vue du faible nombre des dimensions, l’ajout de ces couches ne semble pas être pertinent. 😊 Bien entendu, en les ajoutant, nous pourrions (encore) améliorer les résultats de nos modèles 😊<jupyter_code>import time 

Case_to_train = [
    cambriolage_case,
    murder_case,
    theft_with_hand_case,
    specific_theft_case,
    violent_theft_case,
    simple_theft_case
]

score_type = ["RMSLE_LOG1","RMSLE"]

case = 0
tmp_global = 0
i = 1
for element in Case_to_train:
    print("Dict num " + str(i) + " on " + str(len(Case_to_train)))
    for j in range(3):
        tmps1 = time.time()
        print("\tpre processor " + str(j+1))
        for k in score_type:
            case += 1
            run_dictionnary_case(
                df_main = df_all,
                df_result = df_result,
                dictionary_case = element,
                preprocessor_case = j,
                score_type = k,
                isDisplay = False
            )
        tmps2 = time.time()-tmps1
        tmp_global = tmp_global + tmps2
        print("\tTps exe prepro %f seconde(s)" %tmps2)
    i = i + 1
tmp_global = tmp_global/60
print("tps execution global : %f min(s)" %tmp_global)
print("nb total treat : " + str(case))<jupyter_output>Dict num 1 on 6
	pre processor 1<jupyter_text>Les dictionnaires ont été exécuté, bien entendu, pendant le déroulement du processus, des copies des modèles ont été réalisées en locales. Passons maintenant à l’évaluation de ces modèles. 3.3. Évaluation et comparaisonVoici un aperçu du tableau des résultats.<jupyter_code>print(df_result.shape)
df_result.head(13)<jupyter_output>(384, 9)<jupyter_text>Maintenant rechercherons pour chaque valeur prédite quels sont les meilleurs résultats effectués sur l’année 2020.Voici un exemple de condition possible :acceptable_SCORE_value = 0.3ERR_Moy = 30condition_dict = (df_result['Dictionnaire'] == 'cambriolage_case') condition_VP = (df_result['ValeurPredict'] == 'Total_Cambriolage') condition_SCORE = (df_result['SCORE_Test'] condition_ERR = (df_result['Err_Moy_Test'] condition = condition_dict & condition_VP & condition_SCORE & condition_ERR df_result.loc[condition]Mais nous allons privilégier la simplicité 😊<jupyter_code>best_scores = df_result.groupby(['Dictionnaire','ValeurPredict']).idxmin()['SCORE_Val']
resultats = df_result.loc[best_scores].reset_index().drop(columns=['index'])
resultats<jupyter_output><empty_output><jupyter_text>Nous pouvons tout de suite remarquer que les modèles n’ont pas tous donné le même niveau de résultat. Par exemple, le nombre « total de cambriolage » ou les « Autres vols simples contrent des particuliers dans des locaux ou lieux publics » ont des prédictions très intéressantes. À l’inverse le nombre de vols à la tire lui est l’un des plus mauvais scores de cette synthèse. Mauvais score pouvant être justifié par le confinement.Mise à jour : les premiers résultats (sur janvier à mars) étaient pas mal du tout, cependant lorsque j’ai repris ce projet, les évènements ont amoindri les résultats attendus. Bien entendu, cela a eu un impact sur nos prévisions, les rendant « moins » performantes.<jupyter_code>resultats.loc[resultats['SCORE_Val'] < 0.4]<jupyter_output><empty_output><jupyter_text>3.4. PrédictionMaintenant que nos modèles sont définis, nous allons réaliser un peu de prévision. Nous allons reprendre la première prévision de l’année 2020 puis réaliser une seconde pour cet été (en espérant que le confinement soit terminé d’ici là !).<jupyter_code># Jeu de donnée input
x_values = []

departements = all_name_sheet
months = ['01','02','03','04','05','06','07','08']
year = '2020'

for dep in departements:
    for month in months:
        elem = [dep,year,month]
        x_values.append(elem)

df_prediction = pd.DataFrame(
    data = x_values,
    columns = input_columns
)

# Chargement du modèle
dir_path = 'resultat/model/'
filename = dir_path + 'cambriolage_case_Total_Cambriolage_OHE_year,_Dep,_month_cart_RMSLE_.joblib'
model = load(filename)


# Reprise pre transfo
pre_processor_name, preprocessor = modeling_pre_processor(
    preprocessor_case = 2
)

# Définition pipeline
model_processing = Pipeline(
    steps = [
        ('preprocessor', preprocessor),
        ('classifier', model)
    ])

# Prévision
y_pred = model.predict(df_prediction)

df_prediction["Estimation du Total Cambriolage"] = y_pred
df_prediction<jupyter_output><empty_output><jupyter_text>Focalisons-nous sur le département des Bouches-du-Rhône.<jupyter_code>df_prediction.loc[df_prediction.departement == '13']<jupyter_output><empty_output><jupyter_text>Regardons la différence en fonction des taux d’erreur moyens constatés entre prédiction et réel.<jupyter_code># Condition d'analyse
condition = (df_all['year']==2020) & (df_all['departement']=='13')
df_comp = df_all.loc[condition].set_index('month')

comparaison = df_prediction.loc[df_prediction.departement == '13'].set_index('month')
comparaison["Reel"] = df_comp.loc[:,cambriolage_columns].sum(axis=1)
comparaison["Difference"] = np.abs(comparaison["Estimation du Total Cambriolage"] - comparaison["Reel"])

taux_error = 0.13
cond_1 = (comparaison["Reel"] < round(comparaison["Estimation du Total Cambriolage"] * (1+taux_error)))
cond_2 = (comparaison["Reel"] > round(comparaison["Estimation du Total Cambriolage"] * (1-taux_error)))
condition = cond_1 & cond_2
comparaison["Résultat 1x tx err"] = condition

taux_error = 0.13 * 2
cond_1 = (comparaison["Reel"] < round(comparaison["Estimation du Total Cambriolage"] * (1+taux_error)))
cond_2 = (comparaison["Reel"] > round(comparaison["Estimation du Total Cambriolage"] * (1-taux_error)))
condition = cond_1 & cond_2
comparaison["Résultat 2x tx err"] = condition

comparaison["Intervalle de validation +"] = round(comparaison["Estimation du Total Cambriolage"] * (1+taux_error))
comparaison["Intervalle de validation -"] = round(comparaison["Estimation du Total Cambriolage"] * (1-taux_error))
comparaison<jupyter_output><empty_output><jupyter_text>- Seul le mois de janvier correspond à une prédiction correcte.- Tous les autres mois ont des prédictions supérieures à la réalité (constat pouvant être justifié par la crise sanitaire).- En tenant compte de deux fois, l’erreur moyenne, les mois de janvier, février et avril deviennent des prédictions valides.Malgré la situation actuelle (entrainant une baisse de performance), nous pouvons conclure que ces résultats sont satisfaisants 😊Enfin, regardons les risques d’être touché par un cambriolage. Nous considérons que les risques d’être touché par un cambriolage sont identiques pour tous les habitants de chaque région. Que tous les habitants vivent dans des logements individuels et qu’une personne peut être victime que d’un unique cambriolage par ans (ces faits sont bien entendu faux, cela permet juste de simplifier le calcul). Aussi réalisons une simple division pour faire cette estimation.<jupyter_code>nb_camb_13 = comparaison.iloc[5:8]['Estimation du Total Cambriolage'].sum(axis=0)
nb_pop_13 = df_population.loc[df_population['Departement'] == '13','Total'].values[0]

pourcentage_touche_par_camb = nb_camb_13 / nb_pop_13 * 100

print("Pourcentage d'être touché par un cambriolage cet été (pdv estimation) : " + str(round(pourcentage_touche_par_camb,2)) + " %")<jupyter_output>Pourcentage d'être touché par un cambriolage cet été (pdv estimation) : 0.21 %
{'fraction_non_alphanumeric': 0.12994549384456347, 'fraction_numerical': 0.018184381167183534, 'mean_word_length': 4.39753994420492, 'pattern_counts': {'":': 2, '<': 83, '<?xml version=': 0, '>': 82, 'https://': 4, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '21', 'dir': 'jupyter-structured-clean-dedup', 'id': '653893', 'license': 'MIT', 'n_tokens_mistral': 15054, 'n_tokens_neox': 14527, 'n_words': 3376, 'path': 'P3.ipynb', 'repo_name': 'gjeanner/French-Policy-Analyse', 'size': '42564'}