Environnement - Packages¶
In [176]:
# activer l'environnement
using Pkg
Pkg.activate("env_julia_dtc")
Activating project at `c:\Users\ricco\Desktop\demo\env_julia_dtc`
In [177]:
# liste des packages installés
Pkg.status()
Status `C:\Users\ricco\Desktop\demo\env_julia_dtc\Project.toml` [324d7699] CategoricalArrays v1.1.0 [a93c6f00] DataFrames v1.8.2 [7806a523] DecisionTree v0.12.4 [f526b714] GraphViz v0.2.0 [7073ff75] IJulia v1.34.4 [add582a8] MLJ v0.23.2 [c6f25543] MLJDecisionTreeInterface v0.4.4 [23777cdb] MLJTransforms v0.1.5 [30f210dd] ScientificTypesBase v3.1.0 [2913bbd2] StatsBase v0.34.10 [fdbf4ff8] XLSX v0.11.4
Importation, préparation des données¶
Chargement - Inspection¶
In [178]:
# packages
import DataFrames as DFR
import XLSX
# lecture des données
df = DFR.DataFrame(XLSX.readtable("./data_marketing.xlsx"))
# premières lignes
println(DFR.size(df))
(10000, 16)
In [179]:
# description
println(DFR.describe(df))
16×7 DataFrame Row │ variable mean min median max nmissing eltype │ Symbol Union… Any Union… Any Int64 DataType ─────┼────────────────────────────────────────────────────────────────────────────────────────── 1 │ age 43.5394 18 43.0 69 0 Int64 2 │ revenu_annuel 50134.8 20000.0 49957.2 1.02936e5 0 Float64 3 │ score_credit 679.969 500.0 680.325 850.0 0 Float64 4 │ anciennete_client 9.4085 0 9.0 19 0 Int64 5 │ panier_montant 1509.94 200.0 1494.4 4482.27 0 Float64 6 │ sensibilite_promo 0.500272 0.0 0.49955 0.9999 0 Float64 7 │ frequence_achat 7.504 1 8.0 14 0 Int64 8 │ taux_endettement 35.1021 10.01 35.175 59.99 0 Float64 9 │ region_risque 0.300578 0.1001 0.30215 0.4999 0 Float64 10 │ type_produit automobile electronique 0 String 11 │ canal_achat magasin web 0 String 12 │ nb_cartes_credit 2.1078 1 2.0 6 0 Int64 13 │ incident_paiement 0.3168 0 0.0 1 0 Int64 14 │ epargne 35066.0 4107.22 32519.9 100000.0 0 Float64 15 │ stabilite_emploi 0.697161 0.0 0.7042 1.0 0 Float64 16 │ financement credit_classique paiement_3x 0 String
In [180]:
# schema : types au sens de MLJ
import MLJ
MLJ.schema(df)
┌───────────────────┬────────────┬─────────┐ │ names │ scitypes │ types │ ├───────────────────┼────────────┼─────────┤ │ age │ Count │ Int64 │ │ revenu_annuel │ Continuous │ Float64 │ │ score_credit │ Continuous │ Float64 │ │ anciennete_client │ Count │ Int64 │ │ panier_montant │ Continuous │ Float64 │ │ sensibilite_promo │ Continuous │ Float64 │ │ frequence_achat │ Count │ Int64 │ │ taux_endettement │ Continuous │ Float64 │ │ region_risque │ Continuous │ Float64 │ │ type_produit │ Textual │ String │ │ canal_achat │ Textual │ String │ │ nb_cartes_credit │ Count │ Int64 │ │ incident_paiement │ Count │ Int64 │ │ epargne │ Continuous │ Float64 │ │ stabilite_emploi │ Continuous │ Float64 │ │ financement │ Textual │ String │ └───────────────────┴────────────┴─────────┘
Préparation des structures y vs. X¶
In [181]:
# isoler y et X dans des structures distinctes
y, X = MLJ.unpack(df,==(:financement))
# dimensions
println("Dim. de y = $(DFR.size(y))")
println("Dim. de X = $(DFR.size(X))")
Dim. de y = (10000,) Dim. de X = (10000, 15)
In [182]:
# effectifs par classe
import StatsBase
StatsBase.countmap(y)
Dict{String, Int64} with 3 entries:
"paiement_3x" => 5920
"l_o_a" => 2613
"credit_classique" => 1467
Typage des variables pour la modélisation¶
In [183]:
# typage de la variable cible
import CategoricalArrays as CA
y = CA.categorical(y)
# vérification des modalités
CA.levels(y)
3-element CategoricalArrays.CategoricalArray{String,1,UInt32}:
"credit_classique"
"l_o_a"
"paiement_3x"
In [184]:
# typer correctement les X à modifier
# en les énumérant individuellement
# utilisation du package ScientificTypesBase
import ScientificTypesBase as STB
MLJ.coerce!(X,
:age => STB.Continuous,
:anciennete_client => STB.Continuous,
:frequence_achat => STB.Continuous,
:type_produit => STB.Multiclass,
:canal_achat => STB.Multiclass,
:nb_cartes_credit => STB.Continuous,
:incident_paiement => STB.Continuous)
# schéma
MLJ.schema(X)
┌───────────────────┬───────────────┬──────────────────────────────────┐ │ names │ scitypes │ types │ ├───────────────────┼───────────────┼──────────────────────────────────┤ │ age │ Continuous │ Float64 │ │ revenu_annuel │ Continuous │ Float64 │ │ score_credit │ Continuous │ Float64 │ │ anciennete_client │ Continuous │ Float64 │ │ panier_montant │ Continuous │ Float64 │ │ sensibilite_promo │ Continuous │ Float64 │ │ frequence_achat │ Continuous │ Float64 │ │ taux_endettement │ Continuous │ Float64 │ │ region_risque │ Continuous │ Float64 │ │ type_produit │ Multiclass{3} │ CategoricalValue{String, UInt32} │ │ canal_achat │ Multiclass{3} │ CategoricalValue{String, UInt32} │ │ nb_cartes_credit │ Continuous │ Float64 │ │ incident_paiement │ Continuous │ Float64 │ │ epargne │ Continuous │ Float64 │ │ stabilite_emploi │ Continuous │ Float64 │ └───────────────────┴───────────────┴──────────────────────────────────┘
Codage des descripteurs catégoriels¶
In [185]:
# one-hot encoder pour les descripteurscatégoriels
OneHotEncoder = @MLJ.load OneHotEncoder pkg=MLJTransforms
import MLJTransforms ✔
┌ Info: For silent loading, specify `verbosity=0`. └ @ Main C:\Users\ricco\.julia\packages\MLJModels\9LbNu\src\loading.jl:159
MLJTransforms.OneHotEncoder
In [186]:
# encodage (par défaut, pas de modalité exclue)
# instanciation et préparation
ohe = MLJ.machine(OneHotEncoder(),X)
# entraînement
MLJ.fit!(ohe)
# transformation
XPrim = MLJ.transform(ohe,X)
┌ Info: Training machine(OneHotEncoder(features = Symbol[], …), …). └ @ MLJBase C:\Users\ricco\.julia\packages\MLJBase\krfwA\src\machines.jl:499 ┌ Info: Spawning 3 sub-features to one-hot encode feature :type_produit. └ @ MLJTransforms C:\Users\ricco\.julia\packages\MLJTransforms\rATN1\src\transformers\other_transformers\one_hot_encoder.jl:67 ┌ Info: Spawning 3 sub-features to one-hot encode feature :canal_achat. └ @ MLJTransforms C:\Users\ricco\.julia\packages\MLJTransforms\rATN1\src\transformers\other_transformers\one_hot_encoder.jl:67
10000×19 DataFrame
9975 rows omitted
| Row | age | revenu_annuel | score_credit | anciennete_client | panier_montant | sensibilite_promo | frequence_achat | taux_endettement | region_risque | type_produit__automobile | type_produit__electromenager | type_produit__electronique | canal_achat__magasin | canal_achat__mobile | canal_achat__web | nb_cartes_credit | incident_paiement | epargne | stabilite_emploi |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | 56.0 | 37214.2 | 733.34 | 18.0 | 674.91 | 0.6048 | 3.0 | 17.25 | 0.4908 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 2.0 | 0.0 | 22395.3 | 0.9081 |
| 2 | 69.0 | 57130.5 | 701.2 | 13.0 | 2413.49 | 0.3271 | 6.0 | 29.22 | 0.1043 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 3.0 | 0.0 | 11986.1 | 0.7551 |
| 3 | 46.0 | 59486.8 | 715.98 | 16.0 | 2048.7 | 0.8174 | 12.0 | 49.62 | 0.3656 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 2.0 | 0.0 | 24541.2 | 0.6869 |
| 4 | 32.0 | 42887.3 | 756.3 | 14.0 | 1494.53 | 0.1354 | 1.0 | 31.08 | 0.4172 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 2.0 | 1.0 | 32215.9 | 0.7385 |
| 5 | 60.0 | 38423.4 | 671.0 | 5.0 | 909.72 | 0.8817 | 12.0 | 14.99 | 0.3556 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | 21098.7 | 0.8862 |
| 6 | 25.0 | 74142.8 | 613.07 | 18.0 | 1034.89 | 0.9747 | 12.0 | 14.8 | 0.2092 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 3.0 | 1.0 | 76838.1 | 0.7647 |
| 7 | 38.0 | 53412.4 | 758.07 | 19.0 | 2958.34 | 0.9677 | 4.0 | 21.85 | 0.4291 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 3.0 | 1.0 | 46627.2 | 0.6407 |
| 8 | 56.0 | 59539.5 | 648.21 | 5.0 | 1642.75 | 0.1477 | 9.0 | 38.24 | 0.4653 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 3.0 | 0.0 | 21234.0 | 0.6609 |
| 9 | 36.0 | 37668.9 | 638.58 | 5.0 | 2563.89 | 0.5496 | 2.0 | 51.51 | 0.3734 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 42762.7 | 0.8463 |
| 10 | 40.0 | 31710.7 | 572.23 | 3.0 | 1693.25 | 0.5849 | 2.0 | 36.69 | 0.3044 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 13997.1 | 0.4952 |
| 11 | 28.0 | 41458.2 | 714.28 | 0.0 | 1137.84 | 0.1949 | 2.0 | 47.3 | 0.2465 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 2.0 | 0.0 | 10809.5 | 0.8906 |
| 12 | 28.0 | 48139.7 | 582.71 | 18.0 | 1967.27 | 0.5468 | 10.0 | 42.28 | 0.232 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 2.0 | 1.0 | 33027.9 | 0.3127 |
| 13 | 41.0 | 34036.7 | 634.98 | 10.0 | 3226.27 | 0.6465 | 10.0 | 36.2 | 0.3893 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 2.0 | 1.0 | 21709.4 | 0.7146 |
| ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ |
| 9989 | 41.0 | 54902.5 | 609.66 | 19.0 | 1361.18 | 0.5281 | 3.0 | 41.17 | 0.3285 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 3.0 | 0.0 | 36557.0 | 0.6157 |
| 9990 | 23.0 | 62980.4 | 676.76 | 17.0 | 1133.09 | 0.4147 | 10.0 | 49.29 | 0.4074 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 2.0 | 1.0 | 45079.1 | 1.0 |
| 9991 | 44.0 | 51340.4 | 580.87 | 12.0 | 943.65 | 0.9199 | 14.0 | 29.19 | 0.424 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 2.0 | 0.0 | 19148.5 | 0.8463 |
| 9992 | 35.0 | 64768.6 | 666.04 | 7.0 | 1626.23 | 0.4052 | 8.0 | 54.18 | 0.2328 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 3.0 | 0.0 | 26832.0 | 0.8973 |
| 9993 | 41.0 | 59211.6 | 653.52 | 13.0 | 528.71 | 0.596 | 10.0 | 46.78 | 0.3493 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 2.0 | 0.0 | 59188.2 | 0.7929 |
| 9994 | 54.0 | 44602.4 | 671.94 | 2.0 | 2243.38 | 0.6919 | 8.0 | 40.3 | 0.2743 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 2.0 | 0.0 | 39378.8 | 0.7103 |
| 9995 | 41.0 | 63437.8 | 646.44 | 3.0 | 634.77 | 0.019 | 11.0 | 19.92 | 0.1392 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 3.0 | 0.0 | 33575.5 | 0.891 |
| 9996 | 55.0 | 51372.2 | 589.54 | 10.0 | 486.33 | 0.5909 | 14.0 | 43.51 | 0.3594 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 2.0 | 1.0 | 51140.1 | 0.6452 |
| 9997 | 51.0 | 48408.0 | 658.02 | 6.0 | 1298.16 | 0.518 | 8.0 | 51.69 | 0.335 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 3.0 | 0.0 | 12281.5 | 0.3953 |
| 9998 | 57.0 | 42857.0 | 735.85 | 4.0 | 1202.0 | 0.594 | 4.0 | 46.5 | 0.141 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 1.0 | 1.0 | 11600.2 | 0.6747 |
| 9999 | 64.0 | 52490.3 | 755.69 | 1.0 | 1784.45 | 0.0757 | 7.0 | 38.74 | 0.1283 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 2.0 | 0.0 | 15144.0 | 0.6815 |
| 10000 | 32.0 | 64946.9 | 826.36 | 5.0 | 1567.87 | 0.0556 | 10.0 | 45.73 | 0.1999 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 4.0 | 1.0 | 58678.1 | 1.0 |
In [187]:
# description
DFR.describe(XPrim)
19×7 DataFrame
| Row | variable | mean | min | median | max | nmissing | eltype |
|---|---|---|---|---|---|---|---|
| Symbol | Float64 | Float64 | Float64 | Float64 | Int64 | DataType | |
| 1 | age | 43.5394 | 18.0 | 43.0 | 69.0 | 0 | Float64 |
| 2 | revenu_annuel | 50134.8 | 20000.0 | 49957.2 | 1.02936e5 | 0 | Float64 |
| 3 | score_credit | 679.969 | 500.0 | 680.325 | 850.0 | 0 | Float64 |
| 4 | anciennete_client | 9.4085 | 0.0 | 9.0 | 19.0 | 0 | Float64 |
| 5 | panier_montant | 1509.94 | 200.0 | 1494.4 | 4482.27 | 0 | Float64 |
| 6 | sensibilite_promo | 0.500272 | 0.0 | 0.49955 | 0.9999 | 0 | Float64 |
| 7 | frequence_achat | 7.504 | 1.0 | 8.0 | 14.0 | 0 | Float64 |
| 8 | taux_endettement | 35.1021 | 10.01 | 35.175 | 59.99 | 0 | Float64 |
| 9 | region_risque | 0.300578 | 0.1001 | 0.30215 | 0.4999 | 0 | Float64 |
| 10 | type_produit__automobile | 0.3307 | 0.0 | 0.0 | 1.0 | 0 | Float64 |
| 11 | type_produit__electromenager | 0.3329 | 0.0 | 0.0 | 1.0 | 0 | Float64 |
| 12 | type_produit__electronique | 0.3364 | 0.0 | 0.0 | 1.0 | 0 | Float64 |
| 13 | canal_achat__magasin | 0.3296 | 0.0 | 0.0 | 1.0 | 0 | Float64 |
| 14 | canal_achat__mobile | 0.3359 | 0.0 | 0.0 | 1.0 | 0 | Float64 |
| 15 | canal_achat__web | 0.3345 | 0.0 | 0.0 | 1.0 | 0 | Float64 |
| 16 | nb_cartes_credit | 2.1078 | 1.0 | 2.0 | 6.0 | 0 | Float64 |
| 17 | incident_paiement | 0.3168 | 0.0 | 0.0 | 1.0 | 0 | Float64 |
| 18 | epargne | 35066.0 | 4107.22 | 32519.9 | 100000.0 | 0 | Float64 |
| 19 | stabilite_emploi | 0.697161 | 0.0 | 0.7042 | 1.0 | 0 | Float64 |
Partition TRAIN/TEST - Création des indices¶
In [188]:
# effectif total
n = DFR.nrow(df)
print("Taille de la base = $n")
Taille de la base = 10000
In [189]:
# indices pour partition en train (60%) et test (40%)
# stratify est possible parce y est catégorielle
idTrain, idTest = MLJ.partition(1:n,0.6,shuffle=true,rng=42,stratify=y)
# vérif. dim des identifiants
println("Effectifs TRAIN = $(length(idTrain)) et TEST = $(length(idTest))")
Effectifs TRAIN = 6000 et TEST = 4000
Arbres de décision avec DECISIONTREE (via MLJ)¶
Chargement de la classe de calcul¶
In [190]:
# chargement de la classe de calcul à partir du package
# https://juliaai.github.io/MLJ.jl/stable/models/DecisionTreeClassifier_DecisionTree/#DecisionTreeClassifier_DecisionTree
DecisionTreeClassifier = @MLJ.load DecisionTreeClassifier pkg=DecisionTree
import MLJDecisionTreeInterface ✔
┌ Info: For silent loading, specify `verbosity=0`. └ @ Main C:\Users\ricco\.julia\packages\MLJModels\9LbNu\src\loading.jl:159
MLJDecisionTreeInterface.DecisionTreeClassifier
Instanciation, préparation, entraînement¶
In [191]:
# instanciation avec paramétrage
# limiter la profondeur pour la lisibilité
# attention, mode de calcul de l'importance des variables
# rng pour calcul déterministe (ex. gestion des ex-aequos)
tree = DecisionTreeClassifier(max_depth=3,
feature_importance=:impurity,
rng=42)
# préparation de l'objet pour l'entraînement
# avec la méthode machine() de MLJ
# juste préparatoire => les structures de données sont passées en totalité
mach = MLJ.machine(tree,XPrim,y)
# lancer l'entraînement -> l'objet mach est màj directement avec "!"
# cf. le rôle de "rows" pour indiquer les individus réeelement en TRAIN
# les structures XPrim et y ont été passés préalablement avec machine()
MLJ.fit!(mach,rows=idTrain)
┌ Info: Training machine(DecisionTreeClassifier(max_depth = 3, …), …). └ @ MLJBase C:\Users\ricco\.julia\packages\MLJBase\krfwA\src\machines.jl:499
trained Machine; caches model-specific representations of data
model: DecisionTreeClassifier(max_depth = 3, …)
args:
1: Source @878 ⏎ ScientificTypesBase.Table{AbstractVector{ScientificTypesBase.Continuous}}
2: Source @363 ⏎ AbstractVector{ScientificTypesBase.Multiclass{3}}
Inspection - Fitted params¶
In [192]:
# récupération des résultats
fp = MLJ.fitted_params(mach)
# type de l'objet
typeof(fp)
@NamedTuple{tree::DecisionTree.InfoNode{Float64, UInt32}, raw_tree::DecisionTree.Root{Float64, UInt32}, encoding::Dict{UInt32, CategoricalArrays.CategoricalValue{String, UInt32}}, features::Vector{Symbol}}
In [193]:
# liste des infos
# keys() puisque named tuple
println(keys(fp))
(:tree, :raw_tree, :encoding, :features)
In [194]:
# les noms des variables
fp.features
19-element Vector{Symbol}:
:age
:revenu_annuel
:score_credit
:anciennete_client
:panier_montant
:sensibilite_promo
:frequence_achat
:taux_endettement
:region_risque
:type_produit__automobile
:type_produit__electromenager
:type_produit__electronique
:canal_achat__magasin
:canal_achat__mobile
:canal_achat__web
:nb_cartes_credit
:incident_paiement
:epargne
:stabilite_emploi
In [195]:
# et les modalités de la variable cible
CA.levels(y)
3-element CategoricalArrays.CategoricalArray{String,1,UInt32}:
"credit_classique"
"l_o_a"
"paiement_3x"
In [196]:
# caractéristiques de l'arbre
# avec println()
println(fp.tree)
DecisionTree.InfoNode{Float64, UInt32}(Decision Tree
Leaves: 8
Depth: 3, nchildren=2)
In [197]:
# affichage de l'abre avec le même champ
# on retire simplement le println()
fp.tree
# un affichage graphique avec GraphViz est possible
# mais demande pas mal de contorsions
# un peu comme lors des débuts de SKLEARN sous Python
incident_paiement < 0.5
├─ score_credit < 720.0
│ ├─ panier_montant < 1502.0
│ │ ├─ paiement_3x (1250/1543)
│ │ └─ l_o_a (598/1507)
│ └─ taux_endettement < 34.99
│ ├─ credit_classique (536/636)
│ └─ paiement_3x (230/441)
└─ sensibilite_promo < 0.6952
├─ epargne < 88670.0
│ ├─ paiement_3x (1056/1305)
│ └─ l_o_a (3/3)
└─ revenu_annuel < 30300.0
├─ paiement_3x (50/56)
└─ paiement_3x (369/509)
In [198]:
# ou autre approche
import DecisionTree as TD
DT.print_tree(fp.raw_tree,feature_names=fp.features)
Feature 17: "incident_paiement" < 0.5 ?
├─ Feature 3: "score_credit" < 720.0 ?
├─ Feature 5: "panier_montant" < 1502.0 ?
├─ 3 : 1250/1543
└─ 2 : 598/1507
└─ Feature 8: "taux_endettement" < 34.99 ?
├─ 1 : 536/636
└─ 3 : 230/441
└─ Feature 6: "sensibilite_promo" < 0.6952 ?
├─ Feature 18: "epargne" < 88670.0 ?
├─ 3 : 1056/1305
└─ 2 : 3/3
└─ Feature 2: "revenu_annuel" < 30300.0 ?
├─ 3 : 50/56
└─ 3 : 369/509
Importance des variables¶
In [199]:
# importance des variables
MLJ.feature_importances(mach)
19-element Vector{Pair{Symbol, Float64}}:
:score_credit => 0.25640648078933176
:incident_paiement => 0.2531296205468259
:taux_endettement => 0.2517768495042364
:panier_montant => 0.23019784848167227
:sensibilite_promo => 0.0029514050112553997
:epargne => 0.0029451420461343953
:revenu_annuel => 0.0025926536205439
:age => 0.0
:anciennete_client => 0.0
:frequence_achat => 0.0
:region_risque => 0.0
:type_produit__automobile => 0.0
:type_produit__electromenager => 0.0
:type_produit__electronique => 0.0
:canal_achat__magasin => 0.0
:canal_achat__mobile => 0.0
:canal_achat__web => 0.0
:nb_cartes_credit => 0.0
:stabilite_emploi => 0.0
Inspection - Report¶
In [200]:
# autre manière d'accéder aux résultats avec report()
rm = MLJ.report(mach)
# type de l'object
typeof(rm)
@NamedTuple{classes_seen::CategoricalArrays.CategoricalVector{String, UInt32, String, CategoricalArrays.CategoricalValue{String, UInt32}, Union{}}, print_tree::MLJDecisionTreeInterface.TreePrinter{DecisionTree.Root{Float64, UInt32}}, features::Vector{Symbol}}
In [201]:
# liste des infos
keys(rm)
(:classes_seen, :print_tree, :features)
In [202]:
# autre solution pour affichage de l'arbre
# sans limitation de profondeur (-1)
rm.print_tree(-1)
Feature 17: "incident_paiement" < 0.5 ?
├─ Feature 3: "score_credit" < 720.0 ?
├─ Feature 5: "panier_montant" < 1502.0 ?
├─ 3 : 1250/1543
└─ 2 : 598/1507
└─ Feature 8: "taux_endettement" < 34.99 ?
├─ 1 : 536/636
└─ 3 : 230/441
└─ Feature 6: "sensibilite_promo" < 0.6952 ?
├─ Feature 18: "epargne" < 88670.0 ?
├─ 3 : 1056/1305
└─ 2 : 3/3
└─ Feature 2: "revenu_annuel" < 30300.0 ?
├─ 3 : 50/56
└─ 3 : 369/509
Evaluation en test¶
Prédiction en test¶
In [203]:
# prédiction en test => directement classes prédites
# XPrim a déjà été passé plus haut
# reste à indiquer les indices des individus en test => idTest
pred = MLJ.predict_mode(mach,rows=idTest)
# premières valeurs
pred[1:10]
10-element CategoricalArrays.CategoricalArray{String,1,UInt32}:
"credit_classique"
"l_o_a"
"paiement_3x"
"paiement_3x"
"l_o_a"
"paiement_3x"
"paiement_3x"
"paiement_3x"
"l_o_a"
"credit_classique"
Matrice de confusion¶
In [204]:
# matrice de confusion
mc = MLJ.confusion_matrix(pred,y[idTest])
mc
┌──────────────────────────────────────────────────┐
│ Ground Truth │
┌────────────────┼────────────────┬────────────────┬────────────────┤
│ Predicted │ credit_c… │ l_o_a │ paiement… │
├────────────────┼────────────────┼────────────────┼────────────────┤
│ credit_c… │ 324 │ 65 │ 0 │
├────────────────┼────────────────┼────────────────┼────────────────┤
│ l_o_a │ 247 │ 430 │ 340 │
├────────────────┼────────────────┼────────────────┼────────────────┤
│ paiement… │ 16 │ 550 │ 2028 │
└────────────────┴────────────────┴────────────────┴────────────────┘
Indicateurs¶
In [205]:
# indicateurs de performance
acc = MLJ.accuracy(pred,y[idTest])
err = MLJ.misclassification_rate(pred,y[idTest])
# affichage
println("Accuracy = $acc ; Error Rate = $err")
Accuracy = 0.6955 ; Error Rate = 0.3045
Encapsuler les tâches dans un Pipeline¶
In [206]:
# de nouveau, on peut passer par un pipeline
pipe = OneHotEncoder() |> DecisionTreeClassifier(max_depth=3,rng=42)
# machine -> on passe X natif et non plus XPrim transformé
mach_pipe = MLJ.machine(pipe,X,y)
# entraînement
MLJ.fit!(mach_pipe,rows=idTrain)
# prédiction
pred_pipe = MLJ.predict_mode(mach_pipe,rows=idTest)
# et comparons les approches (pas-à-pas vs. pipeline)
MLJ.confusion_matrix(pred_pipe,pred)
┌ Info: Training machine(ProbabilisticPipeline(one_hot_encoder = OneHotEncoder(features = Symbol[], …), …), …). └ @ MLJBase C:\Users\ricco\.julia\packages\MLJBase\krfwA\src\machines.jl:499 ┌ Info: Training machine(:one_hot_encoder, …). └ @ MLJBase C:\Users\ricco\.julia\packages\MLJBase\krfwA\src\machines.jl:499 ┌ Info: Spawning 3 sub-features to one-hot encode feature :type_produit. └ @ MLJTransforms C:\Users\ricco\.julia\packages\MLJTransforms\rATN1\src\transformers\other_transformers\one_hot_encoder.jl:67 ┌ Info: Spawning 3 sub-features to one-hot encode feature :canal_achat. └ @ MLJTransforms C:\Users\ricco\.julia\packages\MLJTransforms\rATN1\src\transformers\other_transformers\one_hot_encoder.jl:67 ┌ Info: Training machine(:decision_tree_classifier, …). └ @ MLJBase C:\Users\ricco\.julia\packages\MLJBase\krfwA\src\machines.jl:499
┌──────────────────────────────────────────────────┐
│ Ground Truth │
┌────────────────┼────────────────┬────────────────┬────────────────┤
│ Predicted │ credit_c… │ l_o_a │ paiement… │
├────────────────┼────────────────┼────────────────┼────────────────┤
│ credit_c… │ 389 │ 0 │ 0 │
├────────────────┼────────────────┼────────────────┼────────────────┤
│ l_o_a │ 0 │ 1017 │ 0 │
├────────────────┼────────────────┼────────────────┼────────────────┤
│ paiement… │ 0 │ 0 │ 2594 │
└────────────────┴────────────────┴────────────────┴────────────────┘