R: Que vois-je dans les graphiques de dépendance partielle de gbm et RandomForest?

14

En fait, je pensais avoir compris ce que l'on peut montrer un complot avec dépendance partielle, mais en utilisant un exemple hypothétique très simple, je suis devenu plutôt perplexe. Dans le morceau de code suivant, je génère trois variables indépendantes ( a , b , c ) et une variable dépendante ( y ) avec c montrant une relation linéaire étroite avec y , tandis que a et b ne sont pas corrélés avec y . Je fais une analyse de régression avec un arbre de régression boosté en utilisant le package R gbm:

a <- runif(100, 1, 100)
b <- runif(100, 1, 100)
c <- 1:100 + rnorm(100, mean = 0, sd = 5)
y <- 1:100 + rnorm(100, mean = 0, sd = 5)
par(mfrow = c(2,2))
plot(y ~ a); plot(y ~ b); plot(y ~ c)
Data <- data.frame(matrix(c(y, a, b, c), ncol = 4))
names(Data) <- c("y", "a", "b", "c")
library(gbm)
gbm.gaus <- gbm(y ~ a + b + c, data = Data, distribution = "gaussian")
par(mfrow = c(2,2))
plot(gbm.gaus, i.var = 1)
plot(gbm.gaus, i.var = 2)
plot(gbm.gaus, i.var = 3)

Sans surprise, pour les variables a et b, les graphiques de dépendance partielle donnent des lignes horizontales autour de la moyenne de a . Ce qui me laisse perplexe, c'est l'intrigue de la variable c . J'obtiens des lignes horizontales pour les plages c <40 et c > 60 et l'axe y est limité aux valeurs proches de la moyenne de y . Puisque a et b sont complètement indépendants de y (et donc l'importance variable dans le modèle est 0), je m'attendais à ce que cmontrerait une dépendance partielle sur toute sa gamme au lieu de cette forme sigmoïde pour une gamme très restreinte de ses valeurs. J'ai essayé de trouver des informations dans Friedman (2001) "Greedy function approximation: a gradient boosting machine" et dans Hastie et al. (2011) "Elements of Statistical Learning", mais mes compétences mathématiques sont trop faibles pour comprendre toutes les équations et les formules qui s'y trouvent. D'où ma question: qu'est-ce qui détermine la forme du graphique de dépendance partielle pour la variable c ? (Veuillez expliquer avec des mots compréhensibles par un non-mathématicien!)

AJOUTÉ le 17 avril 2014:

En attendant une réponse, j'ai utilisé les mêmes données d'exemple pour une analyse avec R-package randomForest. Les graphiques de dépendance partielle de randomForest ressemblent beaucoup plus à ce que j'attendais des graphiques gbm: la dépendance partielle des variables explicatives a et b varie de manière aléatoire et proche de 50 environ, tandis que la variable explicative c montre une dépendance partielle sur toute sa plage (et sur presque toute la plage de y ). Quelles pourraient être les raisons de ces différentes formes des parcelles de dépendance partielle dans gbmet randomForest?

parcelles partielles de gbm et randomForest

Voici le code modifié qui compare les tracés:

a <- runif(100, 1, 100)
b <- runif(100, 1, 100)
c <- 1:100 + rnorm(100, mean = 0, sd = 5)
y <- 1:100 + rnorm(100, mean = 0, sd = 5)
par(mfrow = c(2,2))
plot(y ~ a); plot(y ~ b); plot(y ~ c)
Data <- data.frame(matrix(c(y, a, b, c), ncol = 4))
names(Data) <- c("y", "a", "b", "c")

library(gbm)
gbm.gaus <- gbm(y ~ a + b + c, data = Data, distribution = "gaussian")

library(randomForest)
rf.model <- randomForest(y ~ a + b + c, data = Data)

x11(height = 8, width = 5)
par(mfrow = c(3,2))
par(oma = c(1,1,4,1))
plot(gbm.gaus, i.var = 1)
partialPlot(rf.model, Data[,2:4], x.var = "a")
plot(gbm.gaus, i.var = 2)
partialPlot(rf.model, Data[,2:4], x.var = "b")
plot(gbm.gaus, i.var = 3)
partialPlot(rf.model, Data[,2:4], x.var = "c")
title(main = "Boosted regression tree", outer = TRUE, adj = 0.15)
title(main = "Random forest", outer = TRUE, adj = 0.85)
user7417
la source
1
Vous voudrez peut-être régler les hyperparamètres d'une touche. Je ne sais pas quel est le nombre d'arbres par défaut en gbm, mais il peut être si petit qu'il n'a pas le temps d'apprendre une courbure saine.
Shea Parkes
@Shea Parkes - Vous avez raison. Le nombre d'arbres par défaut est de 100, ce qui n'était pas suffisant pour générer un bon modèle. Avec 2000 arbres, les parcelles de dépendance partielle de gbm et de forêt aléatoire sont presque identiques.
user7417

Réponses:

7

J'ai passé un peu de temps à écrire mon propre "traceur de fonctions partielles" avant de réaliser qu'il était déjà intégré à la bibliothèque R randomForest.

[EDIT ... mais j'ai ensuite passé un an à créer le package CRAN forestFloor , qui est à mon avis nettement meilleur que les graphiques de dépendance partielle classiques]

Le tracé de fonction partielle est idéal dans les cas comme cet exemple de simulation que vous montrez ici, où la variable explicative n'interagit pas avec d'autres variables. Si chaque variable explicative contribue de manière additive à la cible-Y par une fonction inconnue, cette méthode est idéale pour montrer cette fonction cachée estimée. Je vois souvent un tel aplatissement aux frontières des fonctions partielles.

Quelques raisons: randomForsest a un argument appelé 'nodesize = 5' ce qui signifie qu'aucun arbre ne subdivisera un groupe de 5 membres ou moins. Par conséquent, chaque arbre ne peut pas distinguer avec plus de précision. La couche d'ensachage / amorçage d'ensemple se lisse en votant les nombreuses fonctions de pas des arbres individuels - mais seulement au milieu de la région de données. Près des frontières de l'espace de données représentées, «l'amplitude» de la fonction partielle va chuter. La définition de la taille du nœud = 3 et / ou d'obtenir plus d'observations par rapport au bruit peut réduire cet effet d'aplatissement des bordures ... Lorsque le rapport signal / bruit chute en général dans la forêt aléatoire, l'échelle des prédictions se condense. Ainsi, les prédictions ne sont pas absolument exactes, mais uniquement corrélées linéairement avec la cible. Vous pouvez voir les valeurs a et b comme des exemples de rapport signal / bruit extrêmement faible, et donc ces fonctions partielles sont très plates. C'est une fonctionnalité intéressante de la forêt aléatoire que vous pouvez déjà deviner dans la gamme des prédictions de l'ensemble d'entraînement, à quel point le modèle fonctionne. OOB.predictions est super aussi ..

l'aplatissement de la parcelle partielle dans les régions sans données est raisonnable: comme la forêt aléatoire et CART sont des modélisations basées sur les données, j'aime personnellement le concept selon lequel ces modèles ne sont pas extrapolés. Ainsi, la prédiction de c = 500 ou c = 1100 est exactement la même que c = 100 ou dans la plupart des cas également c = 98.

Voici un exemple de code avec l'aplatissement de la bordure réduit:

Je n'ai pas essayé le paquet gbm ...

voici un code illustratif basé sur votre exemple ...

#more observations are created...
a <- runif(5000, 1, 100)
b <- runif(5000, 1, 100)
c <- (1:5000)/50 + rnorm(100, mean = 0, sd = 0.1)
y <- (1:5000)/50 + rnorm(100, mean = 0, sd = 0.1)
par(mfrow = c(1,3))
plot(y ~ a); plot(y ~ b); plot(y ~ c)
Data <- data.frame(matrix(c(y, a, b, c), ncol = 4))
names(Data) <- c("y", "a", "b", "c")
library(randomForest)
#smaller nodesize "not as important" when there number of observartion is increased
#more tress can smooth flattening so boundery regions have best possible signal to             noise, data specific how many needed

plot.partial = function() {
partialPlot(rf.model, Data[,2:4], x.var = "a",xlim=c(1,100),ylim=c(1,100))
partialPlot(rf.model, Data[,2:4], x.var = "b",xlim=c(1,100),ylim=c(1,100))
partialPlot(rf.model, Data[,2:4], x.var = "c",xlim=c(1,100),ylim=c(1,100))
}

#worst case! : with 100 samples from Data and nodesize=30
rf.model <- randomForest(y ~ a + b + c, data = Data[sample(5000,100),],nodesize=30)
plot.partial()

#reasonble settings for least partial flattening by few observations: 100 samples and nodesize=3 and ntrees=2000
#more tress can smooth flattening so boundery regions have best possiblefidelity
rf.model <- randomForest(y ~ a + b + c, data = Data[sample(5000,100),],nodesize=5,ntress=2000)
plot.partial()

#more observations is great!
rf.model <- randomForest(y ~ a + b + c,
 data = Data[sample(5000,5000),],
 nodesize=5,ntress=2000)
plot.partial()
Soren Havelund Welling
la source
4

Comme mentionné dans les commentaires ci-dessus, le modèle gbm serait mieux avec un certain réglage des paramètres. Un moyen facile de repérer les problèmes dans le modèle et la nécessité de tels paramètres est de générer des tracés de diagnostic. Par exemple, pour le modèle gbm ci-dessus avec les paramètres par défaut (et en utilisant le package plotmo pour créer les tracés), nous avons

gbm.gaus <- gbm(y~., data = Data, dist = "gaussian")
library(plotmo)   # for the plotres function
plotres(gbm.gaus) # plot the error per ntrees and the residuals

qui donne

terrain

Dans le graphique de gauche, nous voyons que la courbe d'erreur n'a pas atteint son point le plus bas. Et dans le graphique de droite, les résidus ne sont pas ce que nous voudrions.

Si nous reconstruisons le modèle avec un plus grand nombre d'arbres

gbm.gaus1 <- gbm(y~., data = Data, dist = "gaussian",
                 n.trees=5000, interact=3)
plotres(gbm.gaus1)

on a

terrain

Nous voyons la courbe d'erreur en bas avec un grand nombre d'arbres, et le tracé des résidus est plus sain. Nous pouvons également tracer les graphiques de dépendance partielle pour le nouveau modèle gbm et le modèle de forêt aléatoire

library(plotmo)
plotmo(gbm.gaus1, pmethod="partdep", all1=TRUE, all2=TRUE)
plotmo(rf.model,  pmethod="partdep", all1=TRUE, all2=TRUE)

qui donne

terrain

Les parcelles du modèle gbm et de la forêt aléatoire sont maintenant similaires, comme prévu.

Stephen Milborrow
la source
3

Vous devez mettre à jour votre interaction.depthparamètre lorsque vous créez votre modèle boosté. La valeur par défaut est 1 et cela provoquera la gbmdivision de toutes les arborescences que l' algorithme construit une seule fois. Cela signifierait que chaque arbre se divise simplement en variables cet qu'en fonction de l'échantillon d'observations qu'il utilise, il se divisera entre 40 et 60.

Voici les parcelles partielles avec interaction.depth = 3

entrez la description de l'image ici

Matt Mills
la source
bon point, il est
Soren Havelund Welling