web-dev-qa-db-fra.com

Différence entre varImp (caret) et importance (randomForest) pour Random Forest

Je ne comprends pas quelle est la différence entre la fonction varImp (package caret) et la fonction importance (package randomForest) pour un modèle de forêt aléatoire:

J'ai calculé un modèle de classification simple RF et lors du calcul de l'importance variable, j'ai constaté que le "classement" des prédicteurs n'était pas le même pour les deux fonctions:

Voici mon code:

rfImp <- randomForest(Origin ~ ., data = TAll_CS,
                       ntree = 2000,
                       importance = TRUE)

importance(rfImp)

                                 BREAST       LUNG MeanDecreaseAccuracy MeanDecreaseGini
Energy_GLCM_R1SC4NG3        -1.44116806  2.8918537            1.0929302        0.3712622
Contrast_GLCM_R1SC4NG3      -2.61146974  1.5848150           -0.4455327        0.2446930
Entropy_GLCM_R1SC4NG3       -3.42017102  3.8839464            0.9779201        0.4170445
...

varImp(rfImp)
                                 BREAST        LUNG
Energy_GLCM_R1SC4NG3         0.72534283  0.72534283
Contrast_GLCM_R1SC4NG3      -0.51332737 -0.51332737
Entropy_GLCM_R1SC4NG3        0.23188771  0.23188771
...

Je pensais qu'ils utilisaient le même "algorithme" mais je ne suis pas sûr pour le moment.

MODIFIER

Afin de reproduire le problème, l’ensemble de données ionosphere (paquetage kknn) peut être utilisé:

library(kknn)
data(ionosphere)
rfImp <- randomForest(class ~ ., data = ionosphere[,3:35],
                       ntree = 2000,
                       importance = TRUE)
importance(rfImp)
             b        g MeanDecreaseAccuracy MeanDecreaseGini
V3  21.3106205 42.23040             42.16524        15.770711
V4  10.9819574 28.55418             29.28955         6.431929
V5  30.8473944 44.99180             46.64411        22.868543
V6  11.1880372 33.01009             33.18346         6.999027
V7  13.3511887 32.22212             32.66688        14.100210
V8  11.8883317 32.41844             33.03005         7.243705
V9  -0.5020035 19.69505             19.54399         2.501567
V10 -2.9051578 22.24136             20.91442         2.953552
V11 -3.9585608 14.68528             14.11102         1.217768
V12  0.8254453 21.17199             20.75337         3.298964
...

varImp(rfImp)
            b         g
V3  31.770511 31.770511
V4  19.768070 19.768070
V5  37.919596 37.919596
V6  22.099063 22.099063
V7  22.786656 22.786656
V8  22.153388 22.153388
V9   9.596522  9.596522
V10  9.668101  9.668101
V11  5.363359  5.363359
V12 10.998718 10.998718
...

Je pense qu'il me manque quelque chose ...

EDIT 2

J'ai compris que si vous faites la moyenne de chaque ligne des deux premières colonnes de importance(rfImp), vous obtenez les résultats de varImp(rfImp):

impRF <- importance(rfImp)[,1:2]
apply(impRF, 1, function(x) mean(x))
       V3        V4        V5        V6        V7        V8        V9 
31.770511 19.768070 37.919596 22.099063 22.786656 22.153388  9.596522 
      V10       V11       V12 
 9.668101  5.363359 10.998718     ...

# Same result as in both columns of varImp(rfImp)

Je ne sais pas pourquoi cela se produit, mais il doit y avoir une explication à cela.

11
Rafa OR

Si nous parcourons la méthode pour varImp:

Vérifiez l'objet:

> getFromNamespace('varImp','caret')
function (object, ...) 
{
    UseMethod("varImp")
}

Obtenez la méthode S3:

> getS3method('varImp','randomForest')
function (object, ...) 
{
    code <- varImpDependencies("rf")
    code$varImp(object, ...)
}
<environment: namespace:caret>


code <- caret:::varImpDependencies('rf')

> code$varImp
function(object, ...){
                    varImp <- randomForest::importance(object, ...)
                    if(object$type == "regression")
                      varImp <- data.frame(Overall = varImp[,"%IncMSE"])
                    else {
                      retainNames <- levels(object$y)
                      if(all(retainNames %in% colnames(varImp))) {
                        varImp <- varImp[, retainNames]
                      } else {
                        varImp <- data.frame(Overall = varImp[,1])
                      }
                    }

                    out <- as.data.frame(varImp)
                    if(dim(out)[2] == 2) {
                      tmp <- apply(out, 1, mean)
                      out[,1] <- out[,2] <- tmp  
                    }
                    out
                  }

Donc, ceci ne renvoie pas strictement randomForest :: importance, 

Il commence par calculer cela, puis ne sélectionne que les valeurs qualitatives contenues dans l'ensemble de données. 

Ensuite, il fait quelque chose d'intéressant, il vérifie s'il ne reste que deux colonnes:

if(dim(out)[2] == 2) {
   tmp <- apply(out, 1, mean)
   out[,1] <- out[,2] <- tmp  
}

Selon la page de manuel varImp:

Forêt aléatoire: varImp.randomForest et varImp.RandomForest sont des enveloppes autour des fonctions d’importance de randomForest et forfaits de fête, respectivement.

Ce n'est clairement pas le cas.


Quant à pourquoi ...

Si nous n’avons que deux valeurs, l’importance de la variable en tant que prédicteur peut être représentée par une seule valeur. 

Si la variable est un prédicteur de g, elle doit également être un prédicteur de b

Cela a du sens, mais cela ne correspond pas à leur documentation sur ce que fait la fonction, donc je signalerais probablement cela comme un comportement inattendu. La fonction tente de vous aider lorsque vous vous attendez à faire le calcul relatif vous-même.

14
Shape

Cette réponse constitue un complément à la solution de @Shape. Je pense que importance suit l’approche bien connue de Breiman pour calculer l’importance variable rapportée sous la forme MeanDecreaseAccuracy, c’est-à-dire que pour l’échantillon en sortie de sac de chaque arbre, calculer la précision de l’arbre, puis permuter les variables les unes après les autres et mesurer la précision après permutation pour calculer la diminution de la précision sans cette variable.
Je n’ai pas trouvé beaucoup d’informations sur le calcul exact de la diminution de l’exactitude propre à la classe dans les premières colonnes, mais je suppose que c’est la classe prédite correctement k/la classe k totale prédite k

Comme @Shape l'explique, varImp ne rapporte pas la MeanDecreaseAccuracy indiquée par importance, mais calcule plutôt la moyenne des diminutions (mises à l'échelle) de la précision de la classe et la rapporte pour chacune des classes. (Pour plus de 2 classes, varImp rapporte uniquement la diminution de précision de la classe.)
Cette approche n’est similaire que si la distribution de la classe est égale. La raison en est que ce n'est que dans le cas équilibré qu'une diminution de la précision d'une classe diminue également la précision de l'autre classe.

library(caret)
library(randomForest)
library(mlbench)

### Balanced sample size ###
data(Ionosphere)
rfImp1 <- randomForest(Class ~ ., data = Ionosphere[,3:35], ntree = 1000, importance = TRUE)

# How importance() calculates the overall decerase in accuracy for the variable
Imp1 <- importance(rfImp1, scale = FALSE)
summary(Ionosphere$Class)/nrow(Ionosphere)
classRatio1 <- summary(Ionosphere$Class)/nrow(Ionosphere)
#      bad      good 
#0.3589744 0.6410256 

# Caret calculates a simple mean
varImp(rfImp1, scale = FALSE)["V3",] # 0.04542253
Imp1["V3", "bad"] * 0.5 + Imp1["V3", "good"] * 0.5 # 0.04542253
# importance is closer to the weighted average of class importances
Imp1["V3", ] # 0.05262225  
Imp1["V3", "bad"] * classRatio1[1] + Imp1["V3", "good"] * classRatio1[2] # 0.05274091

### Equal sample size ###
Ionosphere2 <- Ionosphere[c(which(Ionosphere$Class == "good"), sample(which(Ionosphere$Class == "bad"), 225, replace = TRUE)),]
summary(Ionosphere2$Class)/nrow(Ionosphere2)
classRatio2 <- summary(Ionosphere2$Class)/nrow(Ionosphere2)
#  bad good 
# 0.5  0.5

rfImp2 <- randomForest(Class ~ ., data = Ionosphere2[,3:35], ntree = 1000, importance = TRUE)
Imp2 <- importance(rfImp2, scale = FALSE)

# Caret calculates a simple mean
varImp(rfImp2, scale = FALSE)["V3",] # 0.06126641 
Imp2["V3", "bad"] * 0.5 + Imp2["V3", "good"] * 0.5 # 0.06126641 
# As does the average adjusted for the balanced class ratio
Imp2["V3", "bad"] * classRatio2[1] + Imp2["V3", "good"] * classRatio2[2] # 0.06126641 
# There is now not much difference between the measure for balanced classes
Imp2["V3",] # 0.06106229

Je pense que cela peut être interprété comme une insistance égale sur toutes les classes, alors que importance rapporte les variables comme étant plus importantes si elles sont importantes pour la classe la plus courante. J'ai tendance à être d'accord avec Max Kuhn sur ce point, mais la différence devrait être expliquée quelque part dans la documentation.

4
joha

Je n'ai pas vos données exactes, mais en utilisant des données factices (voir ci-dessous), je ne peux pas reproduire ce problème. Vérifiez peut-être que vous n'avez vraiment rien fait qui puisse affecter vos résultats. Quelle version de R et caret utilisez-vous?

library(caret)
library(randomForest)

# classification - same result
rfImp1 <- randomForest(Species ~ ., data = iris[,1:5],
                    ntree = 2000,
                    importance = TRUE)
importance(rfImp1)
varImp(rfImp1)

# regression - same result
rfImp2 <- randomForest(Sepal.Length ~ ., data = iris[,1:4],
                    ntree = 2000,
                    importance = TRUE)
importance(rfImp2)
varImp(rfImp2)

Mettre à jour:

En utilisant les données Ionosphere, ceci est reproductible:

library(caret)
library(randomForest)
library(mlbench)
data(Ionosphere)
str(Ionosphere)
rfImp1 <- randomForest(Class ~ ., data = Ionosphere[,3:35], ntree = 2000, importance = TRUE)

... avec ces résultats:

> head(importance(rfImp1))

         bad     good MeanDecreaseAccuracy MeanDecreaseGini
V3 20.545836 41.43872             41.26313        15.308791
V4 10.615291 29.31543             29.58395         6.226591
V5 29.508581 44.86784             46.79365        21.757928
V6  9.231544 31.77881             31.48614         7.201694
V7 12.461476 34.39334             34.92728        14.802564
V8 12.944721 32.49392             33.35699         6.971502

> head(varImp(rfImp1))

        bad     good
V3 30.99228 30.99228
V4 19.96536 19.96536
V5 37.18821 37.18821
V6 20.50518 20.50518
V7 23.42741 23.42741
V8 22.71932 22.71932

Mon hypothèse serait que caret et randomForest utilisent simplement différentes méthodes pour agréger les résultats de différentes exécutions pour chaque variable - mais @topepo vous donnera probablement une réponse exacte de toute façon.

2
geekoverdose

https://www.r-bloggers.com/variable-importance-plot-and-variable-selection/ Dans le lien indiqué, il a été démontré que lorsque vous ne spécifiez pas importance = TRUE dans votre modèle, vous obtenez la même diminution moyenne de la valeur de Gini avec les packages randomForest et Caret