/// <summary> /// Parcours un arbre jusqu'à récupérer la catégorie prédite /// </summary> /// <param name="node">Noeud à évaluer</param> /// <param name="data">Tableau à prédire</param> /// <returns>Catégorie prédite pour ce tableau</returns> protected String getCategoryFromTree(RandomForestNode node, double[] data) { if (node.category != null) { return(node.category); } double f = getCosineSimilarity(data, node.classifier, node.paramThreshold); if (f > node.threshold) // = ? { return(getCategoryFromTree(node.left, data)); } else { return(getCategoryFromTree(node.right, data)); } }
protected void makeLeftAndRightNodes(RandomForestNode node, int[] samplesIndexesInLearning) { //On sépare l'échantillon en deux byte[] indicator = splitSample(node, samplesIndexesInLearning); //On récupère l'échantillon séparé dans des tableaux left et right int nLeftVectors = 0; foreach (byte b in indicator) { if (b > 0) { ++nLeftVectors; } } int[] left = new int[nLeftVectors]; int[] right = new int[indicator.Length - nLeftVectors]; int cntL = 0; int cntR = 0; int cnt = 0; foreach (byte b in indicator) { if (b > 0) { left[cntL++] = samplesIndexesInLearning[cnt]; } else { right[cntR++] = samplesIndexesInLearning[cnt]; } ++cnt; } //On affecte les tableaux au noeud actuel après en avoir fait des noeuds node.left = nodeFactory(left); node.right = nodeFactory(right); //Si les nouveaux noeuds ne sont pas des feuilles, on leur crée leurs neouds gauche et droite par récursivité if (node.left.category == null) { makeLeftAndRightNodes(node.left, left); } if (node.right.category == null) { makeLeftAndRightNodes(node.right, right); } }
protected byte[] splitSample(RandomForestNode node, int[] samplesIndexesInLearning) { byte[] indicator = new byte[samplesIndexesInLearning.Length]; int cnt = 0; foreach (int x in samplesIndexesInLearning) { double f = getCosineSimilarity(this._learning[x], node.classifier, node.paramThreshold); indicator[cnt] = (byte)((f >= node.threshold) ? 1 : 0); ++cnt; } bool isAllZeros = true; for (int i = 0; i < samplesIndexesInLearning.Length; ++i) { if (indicator[i] != 0) { isAllZeros = false; break; } } if (isAllZeros == true) { indicator[0] = 1; } bool isAllOnes = true; for (int i = 0; i < samplesIndexesInLearning.Length; ++i) { if (indicator[i] == 0) { isAllOnes = false; break; } } if (isAllOnes == true) { indicator[0] = 0; } return(indicator); }
//Calcule le threshold d'un noeud en faisant la moyenne des similarités cosinus min et max protected double getThreshold(int[] samplesIndexesInLearning, RandomForestNode n) { double fmin = 1000.0; double fmax = -1.0; foreach (int x in samplesIndexesInLearning) { double f = getCosineSimilarity(this._learning[x], n.classifier, n.paramThreshold); if (f < fmin) { fmin = f; } if (f > fmax) { fmax = f; } } return((fmax + fmin) / 2.0); }
protected void populateForest(int forestSize, double[,] samples) { _EventsWorkerCompleted.Clear(); //On trouve combien de thread créer int nbThreads = 8; for (int t = 0; t < nbThreads; t++) { _EventsWorkerCompleted.Add(new System.Threading.AutoResetEvent(false)); int thread = t; Task.Run(() => { int nThread = thread; List <RandomForestNode> trees = new List <RandomForestNode>(); for (int i = 0; i < forestSize / nbThreads; i++) { RandomForestNode result = createTree(samples); trees.Add(result); OnTreeCreated(EventArgs.Empty); } lock (_forest) _forest.AddRange(trees); _EventsWorkerCompleted[nThread].Set(); }); } foreach (var eventWait in _EventsWorkerCompleted) { eventWait.WaitOne(); } //On ajoute les arbres manquants List <RandomForestNode> treesa = new List <RandomForestNode>(); int manquants = forestSize - this._forest.Count; for (int i = 0; i < manquants; i++) { treesa.Add(createTree(samples)); OnTreeCreated(EventArgs.Empty); } lock (_forest) _forest.AddRange(treesa); }
protected RandomForestNode nodeFactory(int[] samplesIndexesInLearning) { //On crée un objet node RandomForestNode node = new RandomForestNode(); //Si il n'y a qu'un echantillon, on est sur une leaf if (samplesIndexesInLearning.Length == 1) { node.category = _learningCategories[(int)samplesIndexesInLearning[0]]; } else //Sinon, on crée la condition { //On tire les paramètres aléatoires parmis tous les paramètres List <int> param = new List <int>(); param.Clear(); int cnt = 0; do { int randomInt; lock (syncLock) { randomInt = this._randomGenerator.Next(_nParameters); } if (!param.Contains(randomInt)) { cnt++; param.Add(randomInt); } } while (cnt < _numberRandomParameters); //Ces paramètres aléatoires serviront à calculer le treshold node.paramThreshold = param; //On crée le classifier node.classifier = makeClassifier(samplesIndexesInLearning); //On calcule le threshold node.threshold = getThreshold(samplesIndexesInLearning, node); } return(node); }
protected RandomForestNode createTree(double[,] samples) { //On récupère les index dans le tableau _learning des _tailleDeSousEchantillonAleatoire échantillons tirés aléatoirement int[] randomSamplesIndexesOutOfTraining = this.getRandomSamplesOutOfTrainingSet(_learning.GetLength(0), _tailleDeSousEchantillonAleatoire); //On récupère une liste numérotée de 0 à _nParameters List <int> param = new List <int>(); for (int j = 0; j < this._nParameters; j++) { param.Add(j); } //On crée un noeud à partir des échantillons aléatoires via la factory RandomForestNode node = this.nodeFactory(randomSamplesIndexesOutOfTraining); //Si on n'est pas arrivé sur une feuille de l'arbre if (node.category == null) { //On crée les branches droites et gauche du noeud this.makeLeftAndRightNodes(node, randomSamplesIndexesOutOfTraining); } //On retourne le noeud return(node); }