web-dev-qa-db-fra.com

Comment améliorer les performances de randomForest?

J'ai un ensemble de formation de taille 38 Mo (12 attributs avec 420000 lignes). J'exécute l'extrait R ci-dessous pour former le modèle à l'aide de randomForest. Cela prend des heures pour moi.

rf.model <- randomForest(
              Weekly_Sales~.,
              data=newdata,
              keep.forest=TRUE,
              importance=TRUE,
              ntree=200,
              do.trace=TRUE,
              na.action=na.roughfix
            )

Je pense qu'en raison de na.roughfix, l'exécution prend beaucoup de temps. Il y a tellement de NA's dans le kit de formation.

Quelqu'un pourrait-il me dire comment puis-je améliorer les performances?

Ma configuration système est la suivante:

Intel(R) Core i7 CPU @ 2.90 GHz
RAM - 8 GB
HDD - 500 GB
64 bit OS
13
user3497321

(Vous devez a) augmenter la taille du noeud à >> 1 et b) exclure les colonnes de caractéristiques de très faible importance, voire même exclure (par exemple) 80% de vos colonnes. Votre problème est presque certainement pas na.roughfix, mais si vous pensez que cela se produit, exécutez na.roughfix séparément en tant qu'étape autonome avant d'appeler randomForest. Éloignez ce hareng rouge au début.)

Maintenant, tous les conseils suivants ne s'appliquent que jusqu'à ce que vous dépassiez les limites de votre mémoire, mesurez donc votre utilisation de la mémoire et assurez-vous de ne pas dépasser. (Commencez avec des paramètres ridiculement petits, puis redimensionnez-les, mesurez le temps d'exécution et continuez à vérifier que cela n'a pas augmenté de manière disproportionnée.)

Les principaux paramètres affectant les performances de randomForest sont:

  • mtry (moins c'est rapide)
  • ntrees
  • nombre d'entités / colonnes dans les données - plus est quadratiquement plus lent ou pire! Voir ci-dessous
  • nombre d'observations/lignes dans les données
  • ncores (plus c'est rapide, tant que l'option parallèle est utilisée)
  • amélioration des performances en attribuant une importance = F et une proximité = F (ne pas calculer la matrice de proximité)
  • N'utilisez jamais la valeur par défaut insensée nodesize=1pour la classification! Dans le package de Breiman, vous ne pouvez pas définir directement maxdepth, mais utiliser nodesize comme proxy et lire tous les bons conseils sur: CrossValidated: "Questions pratiques sur le réglage des forêts aléatoires"
  • Donc ici, vos données ont 4.2e + 5 lignes, alors si chaque nœud ne doit pas être inférieur à ~ 0.01%, essayez nodesize=42. (Commencez par essayer nodesize = 4200 (1%) pour voir à quelle vitesse, puis relancez-le, puis ajustez la taille de la base. Déterminez empiriquement une bonne taille de noeud pour cet ensemble de données.)
  • le temps d’exécution est proportionnel à ~ 2 ^ D_max, c’est-à-dire polynomial à (-log1p (nodesize))
  • éventuellement, vous pouvez également accélérer en utilisant l'échantillonnage, voir strata,sampsize arguments

Ensuite, une estimation du premier temps de l'exécution, indiquant mtry = M, ntrees = T, ncores = C, nfeatures = F, nrows = R, maxdepth = D_max, est la suivante:

Runtime proportional to: T * F^2 * (R^1.something) * 2^D_max / C

(Encore une fois, tous les paris sont désactivés si vous dépassez la mémoire. Essayez également de ne rouler que sur un cœur, puis sur 2, puis sur 4 et vérifiez que vous obtenez une accélération linéaire. Et non un ralentissement.) R est pire que linéaire, peut-être quadratique, car le partitionnement de l’arbre doit prendre en compte toutes les partitions des lignes de données, c’est certainement un peu pire que linéaire. Vérifiez que l’échantillonnage ou l’indexation ne donne que 10% de lignes.

Astuce: conserver un grand nombre de fonctions de faible importance augmente de façon quadratique, ce qui augmente considérablement la durée d'exécution, pour une précision sublinéaire. En effet, à chaque nœud, nous devons considérer toutes les sélections de fonctions possibles (ou peu importe le nombre). Et Au sein de chaque arbre, nous devons considérer toutes les combinaisons possibles de fonctionnalités (F-choice-mtry). Voici donc ma méthodologie, qui consiste à "sélectionner rapidement les fonctionnalités pour améliorer les performances":

  1. générer un arbre normalement (lent), bien que l'on utilise un nodesize=42 sain ou plus grand
  2. regardez rf $ importances ou randomForest::varImpPlot(). Choisissez uniquement les fonctionnalités top-K, où vous choisissez K; pour un exemple stupide-rapide, choisissez K = 3. Enregistrez cette liste entière pour référence future.
  3. maintenant, relancez l’arbre mais ne lui donnez que newdata[,importantCols]
  4. confirmez que la vitesse est quatre fois plus rapide et que l'erreur n'est pas pire
  5. une fois que vous connaissez vos importances variables, vous pouvez désactiver importance=F
  6. Modifiez et réglez les nœuds (modifiez une à la fois), réexécutez et mesurez l’amélioration de la vitesse.
  7. tracez vos résultats de performance sur des axes logarithmiques
  8. postez-nous les résultats! Avez-vous corroboré ce qui précède? Des commentaires sur l'utilisation de la mémoire?

(Notez que ce qui précède n'est pas une procédure statistiquement valide pour la sélection de fonctionnalités réelle; ne vous fiez pas à cela, lisez le package randomForest pour connaître les méthodes appropriées pour la sélection de fonctionnalités basée sur RF.)

50
smci

Je soupçonne que do.trace peut également prendre du temps ... à la place do.trace = TRUE, vous pouvez utiliser do.trace = 5 (pour ne montrer que 5 traces) juste pour avoir une idée des erreurs. Pour les grands ensembles de données, do.trace prendrait également beaucoup de temps.

1
Manoj Kumar