Petal.Length | Species |
---|---|
1.4 | setosa |
1.4 | setosa |
4.7 | versicolor |
4.5 | versicolor |
6.0 | virginica |
5.1 | virginica |
Données + cibles + règles = arbre (...hmm)
clf = sklearn.tree.DecisionTreeClassifier()
# Note : numpy.reshape nécessaire ici...
res = clf.fit(iris.data[[0,1,50,51,100,101],2],
iris.target[[0,1,50,51,100,101]])
graphviz.Source(tree.export_graphviz(clf))
...Avec un peu d'imagination !
library(titanic) ; library(rpart)
# Sélection des variables a priori pertinentes :
# type et prix du billet, âge, sexe. Cible = survie
fit = rpart(Survived ~ Pclass+Fare+Sex+Age,
titanic_train, method="class")
library(rpart.plot) ; rpart.plot(fit)
À partir des données complètes...
...Jusqu'à ce qu'aucune division ne soit possible.
Difficulté = point 1.
Température | Courir ? |
---|---|
12 | oui |
18 | oui |
25 | oui |
27 | oui |
20 | non |
22 | non |
3 | non |
-1 | non |
Température | Courir ? |
---|---|
-1 | non |
3 | non |
12 | oui |
18 | oui |
20 | non |
22 | non |
25 | oui |
27 | oui |
Découpage entre 18 et 20 : température <= 19 ou > 19.
4 lignes de chaque côté : proportions 4/8 et 4/8 (0.5).
2 "oui" et 2 "non" de chaque côté :
$G = 0.5 [ (2/4)^2 + (2/4)^2 ] + 0.5 [ (2/4)^2 + (2/4)^2 ]$
$\quad = 1/2$
Découpage entre 3 et 12 : température <= 7 ou > 7.
2 lignes à gauche, 6 à droite : proportions 2/8 et 6/8.
2 "non" à gauche, 2 "non" + 4 "oui" à droite :
$G = 2/8 [ (2/2)^2 + (0/2)^2 ] + 6/8 [ (2/6)^2 + (4/6)^2 ]$
$\quad = 2/3 > 1/2$
Température | Courir ? |
---|---|
12 | oui |
18 | oui |
25 | oui |
27 | peut-être |
20 | non |
22 | non |
3 | peut-être |
-1 | peut-être |
Température | Courir ? |
---|---|
-1 | peut-être |
3 | peut-être |
12 | oui |
18 | oui |
20 | non |
22 | non |
25 | oui |
27 | peut-être |
Découpage entre 18 et 20 : température <= 19 ou > 19.
4 lignes de chaque côté : proportions 4/8 et 4/8 (0.5).
$G = 0.5 [ (2/4)^2 + (2/4)^2 + (0/4)^2] +$
$\quad\quad 0.5 [ (1/4)^2 + (1/4)^2 + (2/4)^2 ]$
$\quad = 7/16$
Exercice : découpage entre 3 et 12 ?
Météo | Courir ? |
---|---|
soleil | oui |
soleil | oui |
nuages | oui |
nuages | peut-être |
pluie | non |
pluie | non |
neige | peut-être |
neige | peut-être |
Idée 1 : division "une valeur vs. les autres".
exemple : nuages vs. soleil/pluie/neige.
Idée 2 : tester toutes les combinaisons.
exemple : soleil/nuages vs. pluie/neige
Découpage soleil/nuages vs. pluie/neige.
4 lignes de chaque côté : proportions 4/8 et 4/8 (0.5).
$G = 0.5 [ (3/4)^2 + (1/4)^2 + (0/4)^2] +$
$\quad\quad 0.5 [ (0/4)^2 + (2/4)^2 + (2/4)^2 ]$
$\quad = 9/16$
Exercice : découpage soleil/neige vs. nuages/pluie ?
Potentiellement intéressant de découper en + d'un point, mais on se limite aux arbres binaires (plus simples, en général suffisants).
Si données manquantes :
Diviser jusqu'à ne plus pouvoir = surapprentissage.
$\Rightarrow$ Paramètre de contrôle du nombre de divisions.
Mieux : fusionner les noeuds a posteriori
> fit = rpart(Species ~ ., iris, method="class",
control=list(minbucket=1,minsplit=2,cp=0))
> fit$cptable
CP nsplit rel_error xerror xstd
1 0.500 0 1.00 1.20 0.04898979
2 0.440 1 0.50 0.65 0.06069047
3 0.020 2 0.06 0.11 0.03192700
4 0.010 3 0.04 0.11 0.03192700
5 0.005 6 0.01 0.09 0.02908608
6 0.000 8 0.00 0.09 0.02908608
plotcp(fit)
Au lieu de prédire une classe majoritaire, prédire la moyenne des valeurs présentes à cette feuille.
Changement dans l'algorithme : on cherche à minimiser la "variance" au lieu de maximiser $\sum p_k^2$.
Considérant une division comme précédemment,
$V = {\displaystyle \sum_{i \in G} (y_i - m_{G})^2 + \sum_{i \in D} (y_i - m_{D})^2}$
avec $m_G$ et $m_D$ moyennes à gauche et à droite.
Species | Length3 | Weight |
---|---|---|
Bream | 30.0 | 242 |
Bream | 31.2 | 290 |
Roach | 22.2 | 120 |
Roach | 23.1 | 110 |
Roach | 23.7 | 120 |
Perch | 20.2 | 80 |
Perch | 20.8 | 85 |
Perch | 21.0 | 85 |
Poids en fonction de espèce et "longueur" ?
Length3 | 20.2 | 20.8 | 21.0 | 22.2 | 23.1 | 23.7 | 30.0 | 31.2 |
---|---|---|---|---|---|---|---|---|
Weight | 80 | 85 | 85 | 120 | 110 | 120 | 242 | 290 |
Coupure entre 21 et 22.2 :
$V = (80 - m_G)^2 + 2 \times (85 - m_G)^2 +$
$V = $$(120 - m_D)^2 + \dots + (290 - m_D)^2$
Avec $m_G$ et $m_D$ moyennes à gauche / droite.
On trouve $V \simeq 28.10^3$
Coupure entre 23.7 et 30 :
$V = (80 - m_G)^2 + \dots + (120 - m_G)^2 +$
$V = $$(242 - m_D)^2 + (290 - m_D)^2$
On trouve $V \simeq 2900 \ll 28000$
Conclusion: on coupe à $\frac{23.7 + 30}{2} = 26.85$
Species | Perch | Perch | Perch | Roach | Roach | Roach | Bream | Bream |
---|---|---|---|---|---|---|---|---|
Weight | 80 | 85 | 85 | 120 | 110 | 120 | 242 | 290 |
...Mène aux mêmes calculs.
# En se limitant aux variables Species et Length3
fit = rpart(Weight ~ Species + Length3, Fish, method="anova")
# Avec toutes les variables
fit = rpart(Weight ~ ., Fish, method="anova")
rpart.plot(fit)
plotcp(fit)
# En régression :
p <- predict(fit, newData, type="anova")
# En classification :
p <- predict(fit, newData, type="class")
Comparez les approches $k$ plus proches voisins et arbres de décision sur les jeux de données iris puis Fish (en classification).
Dataset autos.
Récupérez le jeu de données adult (entraînement + test). L'ensemble d'entraînement comporte des données manquantes :
Dans les deux cas, il faut estimer l'erreur sur l'ensemble de test.
Conclusion ?