FR Tanagra Scikit Learn Decision Tree 2
FR Tanagra Scikit Learn Decision Tree 2
FR Tanagra Scikit Learn Decision Tree 2
1 Introduction
Implémentation des arbres de décision avec la librairie Scikit-Learn (0.22.1) sous Python.
Tous les ans, préalablement à chacune de mes séances sur machine avec les étudiants, je fais un travail de
mise à jour des instructions et indications de résultats retranscrits dans ma fiche de TD (travaux dirigés). Il
faut dire que les packages sous R et Python ne se soucient pas toujours de compatibilités descendantes ou
ascendantes. Une instruction valable hier peut ne pas fonctionner aujourd’hui ou, pire, fournir un résultat
différent parce que les paramètres par défaut ont été modifiés ou les algorithmes sous-jacents améliorés. La
situation est moins critique lorsque des fonctionnalités additionnelles sont proposées. Encore faut-il les
connaître. La veille technologique est indissociable de notre activité, et j’y passe vraiment beaucoup de
temps.
Concernant ma séance consacrée aux arbres de décision sous Python justement, où nous utilisons la libraire
Scikit-Learn (Decision Trees), j’avais pour habitude d’annoncer à mes étudiants qu’il n’était pas
possible de disposer – simplement – d’une représentation graphique de l’arbre, à l’instar de ce que nous
fournirait le package ‘’rpart.plot’’ pour les arbres ‘’rpart’’ sous R par exemple. La nécessité d’installer un
outil externe (voir ‘’Random Forest et Boosting avec R et Python’’, novembre 2015 ; section 4.3.3)
rendait la manipulation rédhibitoire dans une séance où nous travaillons en temps (très) restreint avec des
machines (très) protégées. Je me suis rendu compte récemment au détour d’une requête Google, assez
heureuse je dois l’avouer, que la situation a évolué avec la version 0.21.0 de Scikit-Learn (Mai 2019).
Nous allons vérifier cela dans ce tutoriel. Nous en profiterons pour étudier les manipulations à réaliser
pour pouvoir appliquer les dits-arbres sur des variables prédictives (explicatives) catégorielles. L’outil ne
sait pas les appréhender de manière native… pour l’instant (version 0.22.1, février 2020).
Nous devrions commencer toute session d’analyse avec l’identification des versions des packages que nous
utilisons. Concernant ‘’scikit-learn’’, nous travaillons avec…
0.22.1
Nous traitons un exemple très simple dans un premier temps. Nous utilisons la base ultra-connue ‘’Breast
Cancer Wisconsin’’. Nous cherchons à expliquer la variable ‘’classe’’ décrivant la nature maligne
(malignant) ou non (begnin) de cellules à partir de leurs caractéristiques (clump, ucellsize, …, mitoses ; 9
variables numériques).
(699, 10)
Nous disposons de 699 observations et 10 variables. Voici les premières lignes de notre dataset.
s variables
La variable cible ‘’classe’’ est la seule non-numérique, le type ‘’object’’ lui est associé.
Nous affichons la fréquence absolue des classes…
begnin 458
malignant 241
Name: classe, dtype: int64
… puis relative.
begnin 0.655222
malignant 0.344778
Name: classe, dtype: float64
Ces informations sont importantes lorsque nous aurons à inspecter les résultats.
Nous cherchons à appliquer le schéma type de l’analyse prédictive : scinder les données en échantillons
d’apprentissage et de test, développer le modèle (estimer ses paramètres) sur le premier, en évaluer les
performances sur le second à travers la confrontation des classes observées et prédites.
Y = f(X1,X2,…) +
Mesures de
Ensemble
de données performances par confrontation entre Y et Y^ : matrice de confusion +
(dataset) (Y ,Yˆ )
Y : valeurs observées
Ensemble de test
Y^ : valeurs prédites par f(.)
Nous souhaitons réserver 399 observations pour l’apprentissage et 300 pour le test, avec un échantillonnage
stratifié (stratify) c.-à-d. respectant les proportions des classes dans les deux sous-ensembles. Nous fixons
(random_state = 1) pour que l’expérimentation soit reproductible.
begnin 0.654135
malignant 0.345865
Name: classe, dtype: float64
… et en test.
begnin 0.656667
malignant 0.343333
Name: classe, dtype: float64
#instanciation de l'arbre
from sklearn.tree import DecisionTreeClassifier
arbreFirst = DecisionTreeClassifier(min_samples_split=30,min_samples_leaf=10)
Nous lançons le processus de modélisation sur les données d’apprentissage en spécifiant la matrice (X)
des variables prédictives, et le vecteur (y) de la variable cible.
#constr
arbreFi
DecisionTreeClassifier(ccp_alpha=0.0, class_weight=None, criterion='gini',
max_depth=None, max_features=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_
La console affiche l’ensemble des paramètres utilisés lors de la modélisation.
L’affichage de l’arbre était un des obstacles de l’utilisation de cet outil. Auparavant, il fallait générer un
fichier au format particulier (.dot), que l’on faisait interpréter par un outil externe à installer au préalable.
Ce n’était pas vraiment ‘’user friendly’’. Aujourd’hui, depuis la version 0.21 de Scikit-Learn, nous
disposons d’une fonction dédiée à la génération de la représentation graphique directement dans la console.
Voyons ce qu’il en est.
La fonction prend en paramètre l’arbre généré par l’apprentissage, la liste des noms des variables
prédictives (feature_names), les sommets peuvent être coloriés selon la classe majoritaire (filled = True).
Racine de l’arbre
1
Yes No
c.-à-d. ucellsize ≤ 3.5 c.-à-d. ucellsize > 3.5
2 3
5 6 7
9 10 11
8
Que lisons-nous ?
L’arbre est composé de 7 feuilles (sommets n°12, 13, 9, 5, 6, 10, 11). Il produit donc 7 règles
prédictives matérialisées par les chemins partant de la racine aux feuilles.
Nous observons l’effectif de l’échantillon d’apprentissage sur la racine de l’arbre (nRacine = n =
samples = 399) avec 261 ‘’begnin’’ et 138 ‘’malignant’’ (dans l’ordre alphabétique).
Les sommets sont teintés (c’est le rôle de l’option filled = True) selon la classe majoritaire qu’ils
portent, avec plus ou moins d’intensité selon la concentration des effectifs. Ici, visiblement, le bleu est
dévolu à ‘’malignant’’, l’orange à ‘’begnin’’.
La concentration des classes est calculée à l’aide de l’indice de Gini (on parle aussi de mesure
d’impureté [de l’anglais ‘’impurity’’] ou de mesure de diversité). Pour la racine (sommet n°1), nous
avons (K = 2, nombre de modalités de la variable ‘’classe’’) :
𝐾 𝑛𝑘,𝑅𝑎𝑐𝑖𝑛𝑒 𝑛𝑘,𝑅𝑎𝑐𝑖𝑛𝑒 261 261 138 138
𝐺(𝑅𝑎𝑐𝑖𝑛𝑒) = ∑ (1 − )= (1 − ) (1 − ) = 0.452
𝑛𝑅𝑎𝑐𝑖𝑛𝑒 𝑛𝑅𝑎𝑐𝑖𝑛𝑒 399 399 + 399 399
𝑘=1
‘’ucellsize’’ est la variable de segmentation sur la racine, avec la condition ‘’ucellsize ≤ 3.5’’.
La branche gauche de la racine (sommet n°2) correspond à la proposition vraie de la condition c.-à-d.
ucellsize ≤ 3.5. Nous lisons sur le sommet enfant qu’elle correspond à (samples = 273) observations,
avec 253 ‘’begnin’’ et 20 ‘’malignant’’. Nous avons G(sommet)
= 0.136. Plus la valeur de l’indice de Gini est faible, plus les classes sont concentrées sur un
sommet.
Lorsque les variables de segmentation sont quantitatives, il n’est pas rare qu’elles interviennent
plusieurs fois dans l’arbre, mais avec des seuils de découpage différents. C’est le cas de variables
‘’ucellsize’’ et ‘’bnuclei’’ ici.
Nous pouvons simplifier l’arbre en retirant les feuilles issues du même père qui portent des conclusions
identiques. En procédant ainsi de bas en haut (bottom-up), nous effectuons un processus (simplifié) de
post-élagage qui permet de réduire la taille de l’arbre sans modifier en aucune manière ses propriétés
prédictives. Suivant cette idée, nous devrions aboutir à un arbre avec 3 feuilles dans notre exemple,
avec exactement le même comportement en classement. Nous y reviendrons plus bas en modifiant les
paramètres d’apprentissage (section 0).
Clairement, la possibilité d’afficher l’arbre sous une forme graphique à l’aide d’instructions simples joue
énormément en faveur de l’attractivité de l’outil. L’absence de cette fonctionnalité constituait une des
critiques récurrentes des pro-R (rpart / rpart.plot) par rapport au tandem Python / Scikit-Learn. Elle vient
d’être balayée.
2.6 Affichage sous forme de règles imbriquées de l’arbre
L’affichage graphique est sympathique mais devient peu lisible dès lors que la taille de l’arbre augmente.
Scikit-Learn propose une sortie alternative textuelle, sous la forme de règles imbriquées, à la manière de la
surcharge de la fonction print() de rpart sous R.
Le paramètres de la fonction sont identiques à celle de l’affichage graphique, mais il n’est plus question de
colorier les sommets bien évidemment. Nous demandons à ce que les effectifs sur les feuilles soient
spécifiées (show_weights = True).
(J’ai colorié les feuilles à la main) En faisant le parallèle avec l’arbre graphique ( Figure 2), nous
distinguons bien les successions de segmentations. Les effectifs sur les feuilles correspondent bien
évidemment.
Autre outil d’interprétation, Scikit-Learn peut afficher l’importance des variables, en s’en tenant
exclusivement à celles qui apparaissent explicitement dans l’arbre, contrairement à d’autres outils (‘’rpart’’
de R par exemple qui s’appuie sur le mécanisme du ‘’surrogate variables’’).
Nous récupérons le champ ‘’.feature_importances_’’ de l’arbre que nous plaçons dans un data frame
Pandas pour pouvoir afficher les contributions des variables associées à leurs noms, et triées de manière
décroissante.
#importance des variables
impVarFirst={"Variable":df.columns[:-1],"Importance":arbreFirst.feature_importances_}
print(pandas.DataFrame(impVarFirst).sort_values(by="Importance",ascending=False))
Variable Importance
1 ucellsize 0.816627
5 bnuclei 0.158477
2 ucellshape 0.024243
3 mgadhesion 0.000653
0 clump 0.000000
4 sepics 0.000000
6 bchromatin 0.000000
7 normnucl 0.000000
8 mitoses 0.000000
Sans surprise, seules les variables qui apparaissent dans l’arbre présentent une valeur non-nulle.
‘’ucellsize’’ est la plus importante, puis viennent ‘’bnuclei’’, ‘’ucellshape’’ et, très marginalement,
‘’mgadhesion’’. Comment sont calculées ces valeurs ?
La qualité globale de l’arbre peut être quantifiée par la différence entre l’indice de Gini de la racine
(n°1), et la moyenne pondérée des Gini des L feuilles (n°12, 13, 9, 5, 6, 10, 11), chacune avec un effectif nl
:
𝐿
𝑛𝑙
Δ𝐴𝑟𝑏𝑟𝑒 = 𝐺(𝑅𝑎𝑐𝑖𝑛𝑒) − ∑ 𝐺(𝑙)
𝑛
𝑙=1
232 15 16 84
Δ𝐴𝑟𝑏𝑟𝑒 = 0.452 − ( × 0.0 + × 0.124 + ⋯ + × 0.117 + × 0.0) = 0.40284608
399 399 399 399
Cette quantité peut être également exprimée sous la forme d’une somme pondérée des
Pour mesurer la contribution d’une segmentation dans l’arbre, nous effectuons la différence entre l’indice
de Gini du sommet à segmenter et la moyenne pondérée des Gini de ses feuilles. Cette différence étant
pondérée par le poids du sommet traité.
Pour le sommet n°4 où la variable ‘’ucellshape’’ intervient, et qui a généré les sommets n°8 et 9, nous
avons :
259 247 12
∆𝑠𝑒𝑔𝑚𝑒𝑛𝑡𝑎𝑡𝑖𝑜𝑛= × [0.045 − ( × 0.008 + × 0.486)] = 0.00976634
399 259 259
Elle correspond également à la contribution de la variable dans l’arbre si elle n’apparaît qu’une
seule fois.
Cette valeur est ensuite ramenée à la qualité globale de l’arbre pour que la somme des
0.00976634
𝐶𝑇𝑅(𝑢𝑐𝑒𝑙𝑙𝑠ℎ𝑎𝑝𝑒) = = 0.024243
0.40284608
Et c’est bien la valeur associée à ‘’ucellshape’’ dans le tableau de ‘’feature importances’’ proposé
par Scikit-Learn.
Lorsqu’une variable apparaît plusieurs fois, nous additionnons les contributions des segmentations dans
lesquelles elle intervient. Pour ‘’ucellsize’’ par exemple, qui opère lors des partitions des sommets n° 1 et
3, nous avons…
0.3289749 + 0.00695077
𝐶𝑇𝑅(𝑢𝑐𝑒𝑙𝑙𝑠𝑖𝑧𝑒) = = 0.816627
0.40284608
Pour évaluer les performances prédictives de l’arbre, nous l’appliquons sur l’échantillon test composé
de 300 observations. Nous obtenons une prédiction :
Mais est-ce à juste titre ? Pour le savoir, nous confrontons les classes observées et prédites via la matrice de
confusion.
2.8.2 Matrice de confusion
Nous aurions pu utiliser un outil tableau croisé standard, type ‘’crosstab’’ de la librairie Pandas, mais
‘’Scikit-Learn’’ propose un module dédié ‘’metrics’’ qui se charge de toute la partie évaluation des
classifieurs. Nous aurions tort de nous en priver.
#matrice de confusion
from sklearn import metrics print(metrics.confusion_matrix(dfTest.classe,predFirst))
[[1898]
[ 10 93]]
Les lignes et colonnes sont dans l’ordre alphabétique des modalités. De fait, avec les étiquettes,
classes prédictes
begnin malignant
classes
begnin 189 8
observées
malignant 10 93
Le rappel ou sensibilité :
#F1-score
print(metrics.f1_score(dfTest.classe,predFirst,pos_label='malignant'))
0.911764705882353
Rapport de prédiction. Scikit-Learn propose un rapport global intégrant ces différents éléments avec la
fonction classification_report() :
#rapport de prédiction
print(metrics.classification_report(dfTest.classe,predFirst))
precision recall f1-score support
Notre arbre (Figure 2) paraît surdimensionné. Nous avions remarqué notamment que plusieurs feuilles
issues du même sommet père portaient des conclusions identiques.
Dans cette section, nous introduisons un nouveau paramètre pour réduire la taille de l’arbre. Nous
spécifions (max_leaf_nodes = 3) c.-à-d. nous souhaitons obtenir un arbre qui produit 3 règles au maximum.
Dixit la documentation, l’outil effectue en priorité les segmentations qui maximisent les contributions.
#construction de l'arbre
arbreSecond.fit(X = dfTrain.iloc[:,:-1], y = dfTrain.classe)
#matrice de confusion
print(metrics.confusion_matrix(dfTest.classe,predSecond))
[[1898]
[ 10 93]]
… puisque nous obtenons exactement la même matrice de confusion sur l’échantillon test, et par
conséquent des valeurs identiques des indicateurs de performances.
#taux de reconnaissance
print(metrics.accuracy_score(dfTest.classe,predSecond))
0.94
Nous traitons une version simplifiée de la base ‘’Congressional Voting Records’’ maintenant. Elle
recense les votes de parlementaires américains {(y)es, (n)o, (_?) on ne sait ce qu’ils ont voté} qui sont
repartis en 2 groupes politiques {democrat, republican} que l’on cherche à identifier.
Nous chargeons et inspectons les données.
#dimensions
print(dfVote.shape) #(435, 7)
‘’groupe’’ est la variable cible. Les autres sont les thèmes sur lesquels les parlementaires se sont prononcés.
Pandas attribue le type ‘’object’’ pour ces variables dont les valeurs sont représentées par des chaînes de
caractères comme nous le constatons en affichant les premières lignes. Pandas propose l’équivalent du
‘’factor’’ de R avec le type ‘’category’’, mais les variables n’ont pas été encodées en ce sens lors de notre
importation avec les options par défaut.
A priori, les algorithmes d’arbres de décision n’ont aucun problème à manipuler les variables prédictives
qualitatives. C’est le cas de la très grande majorité des logiciels. Confiants, nous instancions un arbre de
décision avec une profondeur maximale de 3 (max_depth = 3) pour faciliter sa lecture, l’essentiel étant
ailleurs dans cette section.
#instanciation de l'arbre
from sklearn.tree import DecisionTreeClassifier
arbreVote = DecisionTreeClassifier(max_depth = 3)
#construction de l'arbre
arbreVote.fit(X = dfVote.iloc[:,:-1], y = dfVote.groupe)
Patatras ! L’interpréteur nous annonce qu’il ne sait pas convertir les valeurs proposées en flottant. En
effectuant quelques recherches sur le web, je me suis rendu compte que l’outil ne sait pas appréhender les
explicatives non-numériques à ce jour (version 0.22.1, février 2020). On est mal. Il faut passer par un
recodage. Mais de quel type ?
Codage 0/1 des prédictives. Je propose de passer par un codage disjonctif complet (‘’Codage
disjonctif complet’’, mars 2008) c.-à-d. un codage 0/1 où toutes les modalités sont représentées (ce qui
n’est pas le cas dans le tutoriel sur la régression logistique que j’ai mis en lien, une des modalités sert de
référence). Nous énumérons tout d’abord les colonnes constituant la base pour mieux situer les opérations
qui viendront.
#liste des variables
print(dfVote.columns)
Index(['adoption_of_the_budget_re', 'physician_fee_freeze', 'mx_missile', 'superfund_right_to_su
dtype='object')
Nous devons recoder toutes les variables, sauf la cible ‘’groupe’’ qui est en dernière position. Pour
recoder les variables, nous utilisons la fonction get_dummies() de la librairie Pandas.
adoption_of_the_budget_re
uint8 uint8 uint8 uint8 uint8
? 435
uint8
non-null
uint8 uint8 uint8 uint8 uint8 uint8 uint8 uint8 uint8 uint
adoption_of_the_budget_re_n435
uint8 non-null
adoption_of_the_budget_re_y435 non-null
physician_fee_freeze ?435 non-null
physician_fee_freeze_n435 non-null
physician_fee_freeze_y435 non-null
mx_missile ?435 non-null
mx_missile_n435 non-null
mx_missile_y435 non-null
superfund_right_to_sue ?435 non-null
superfund_right_to_sue_n435 non-null
superfund_right_to_sue_y435 non-null
crime ?435 non-null
crime_n435 non-null
crime_y435 non-null
duty_free_exports ?435 non-null
duty_free_exports_n435 non-null
duty_free_exports_y435 non-null
dtypes: uint8(18)
Toutes les variables maintenant sont des indicatrices 0/1 codées en entier. Nous remarquons également
que, pour chaque variable, toutes les modalités sont représentées (y, n, _?).
Vérification pour la variable ‘’crime’’. Pour vérifier l’opération, nous nous intéressons à la
variable ‘’crime’’. Nous affichons la fréquence relative de ses modalités.
Et, effectivement, nous avons les bonnes valeurs pour la variable ‘’crime’’. Il n’y a pas de pertes
d’informations durant le recodage.
Compléter la base avec la variable cible. Nous complétons la base avec la variable cible
‘’groupe’’, qu’il n’était pas nécessaire de recoder, mais qui fait partie de l’analyse.
Des 7 variables initiales, nous travaillons maintenant avec une base comportant 18 variables.
Remarque sur le schéma apprentissage-test. J’ai toujours pour habitude de dire aux étudiants qu’il
faut calculer tous les paramètres de recodage sur l’échantillon d’apprentissage avant de l’appliquer sur
l’échantillon test. Ce principe ne s’applique pas ici puisque nous n’effectuons aucun calcul à partir des
données pour procéder au recodage. Dans le cas présent, qui est particulier, il est donc possible de réaliser
ce pré-traitement sur la totalité de la base avant de partitionner le dataset en échantillons d’apprentissage et
de test.
Nous créons une nouvelle instance de l’arbre de décision et nous lançons la modélisation sur la totalité des
données. Il s’agit avant tout d’un exercice de style destiné à montrer l’intérêt du codage disjonctif complet
ici, le schéma apprentissage-test n’a pas lieu d’être.
physician_fee_freeze != ‘y’
physician_fee_freeze %in% {‘n’, ’_?’} physician_fee_freeze == ‘y’
Elle est segmentée avec la condition (physician_fee_freeze_y ≤ 0.5). C’est variable 0/1
La branche gauche est activée lorsque la condition est vérifiée c.-à-d. lorsque
(physician_fee_freeze_yes == 0) puisqu’elle est binaire. Si l’on revient à la variable initiale, cette
condition correspond donc à (physician_fee_freeze != ‘y’).
A contrario, la branche droite est activée lorsque (physician_fee_freeze_y > 0.5) c.-à.-d.
(physician_fee_freeze_y == 1), ou encore (physician_fee_freeze == ‘y’).
Sous la forme d’un tableau croisé sur la variable originelle, voici le fruit de la segmentation de la
racine :
physician_fee_freeze
n, _? y
Group
democrat 253 14
republican 5 163
Remarque : Notons que cette transformation n’est pas anodine. L’algorithme explore différemment
l’espace des solutions. Surtout lorsque leur nombre est élevé, plutôt qu’un regroupement binaire des
modalités, nous avons – conséquence du recodage – une stratégie ‘’une modalité contre les autres’’. Ce
n’est pas mieux ou moins bien, c’est tout simplement différent, et elle (cette stratégie) a un impact sur les
résultats.
#dimensions
print(dfHeart.shape)
Outre la variable cible ‘’heart’’, forcément qualitative, nous disposons de 6 variables prédictives
qualitatives (object : sexe, type_douleur, sucre, electro, angine, vaisseau) et 6 quantitatives (numériques :
age, pression, cholester, taux_max, depression, pic).
L’idée serait donc de repérer automatiquement les prédictives qualitatives, de les coder en 0/1, puis de les
intégrer dans un nouveau data frame en compagnie des quantitatives.
Pour identifier les qualitatives, nous parcourons les variables prédictives candidates et nous comparons leur
type avec la constante ‘’object_’’ de la librairie Numpy (https://docs.scipy.org/doc/numpy-
1.13.0/reference/arrays.dtypes.html).
Nous leur appliquons un codage disjonctif complet pour obtenir un nouveau data frame.
Nous construisons par ailleurs la liste des variables numériques (différent de ‘object_’).
Et nous n’oublions pas bien sûr de lui associer la variable cible ‘’cœur’’.
able cible
dfHeart.coeur print(dfNew.info())
re.frame.DataFrame'> RangeIndex: 270 entries, 0 to 269 Data columns (total 24 columns):
ount Dtype
Nous pouvons dès lors élaborer l’arbre de décision. Nous limitons sa profondeur à (max_depth = 2) pour en
faciliter la lecture.
#instanciation de l'arbre
from sklearn.tree import DecisionTreeClassifier
arbreHeart = DecisionTreeClassifier(max_depth = 2)
#construction de l'arbre
arbreHeart.fit(X = dfNew.iloc[:,:-1], y = dfNew.coeur)
type_douleur != ‘D’
type_douleur %in% {‘A’, ’B’, ‘C’} type_douleur == ‘D’
La segmentation de la racine de l’arbre porte sur la variable recodée ‘’type_douleur_D’’ c.-à-d. la présence
ou non de la modalité ‘D’ pour la variable ‘’type_douleur’’. Avec :
- Sur la branche gauche les observations répondant à la condition (type_douleur_D ≤ 0.5) soit
(type_douleur != ‘D’) ou encore (type_douleur ϵ {‘A’, ‘B’, ‘C’}).
- La branche droite correspond à la condition (type_douleur_D > 0.5) soit (type_douleur = ‘D’).
Nous observons que les descripteurs quantitatifs et qualitatifs (sous leur forme recodée) apparaissent
maintenant de manière indifférenciée dans l’arbre.
Remarque : Comme pour les bases à variables prédictives exclusivement qualitatives, nous pouvons
effectuer l’opération de transformation avant de procéder à la partition des données en échantillons
d’apprentissage et de test.
5 Conclusion
Les packages évoluent et c’est tant mieux. Il faut suivre simplement. Dans ce tutoriel, nous avons exploré
une nouvelle fonctionnalité de Scikit-Learn pour Python, la possibilité de représenter graphiquement un
arbre de décision avec des commandes succinctes, sans utilisation d’outils additionnels. Nous en avons
profité pour montrer comment appréhender les variables explicatives catégorielles qui ne sont pas, à l’heure
actuelle (février 2020), supportées nativement par la classe de calcul.
6 Références
Scikit-Learn, ‘’Decision Trees’’, https://scikit-learn.org/stable/modules/tree.html
R. Rakotomalala, ‘’Arbres de décision’’, Revue Modulad, numéro 33, pp. 163-187, 2005.