Forêt aléatoire équilibrée en python

À propos de Random Forest

Random Forest est un algorithme d'apprentissage en groupe qui utilise un arbre de décision comme une machine d'apprentissage faible et qui est l'une des méthodes d'apprentissage automatique typiques. La quantité d'entités et les données d'observation sont échantillonnées pour créer un arbre de décision. Si vous le recherchez, vous en trouverez beaucoup, je vais donc omettre les algorithmes ici.

Problèmes d'application aux données déséquilibrées

Par exemple, si vous essayez de classer les données de 1 000 cas positifs et de 50 cas négatifs par Random Forest, vous ne pouvez pas l'utiliser comme classificateur à moins que vous ne preniez certaines mesures. Il peut également être géré en pondérant les données déséquilibrées (ajustable en tant que paramètre class_weight pour RandomForest dans scikit-learn) Cependant, il est possible que le poids d'une donnée soit trop important et qu'un surentraînement puisse se produire.

Qu'est-ce que la forêt aléatoire équilibrée?

Par conséquent, il existe une méthode pour traiter des données déséquilibrées en ajustant le nombre d'échantillons pour chaque arbre de décision. (Dans l'exemple précédent, par exemple, pour chaque arbre de décision, 50 exemples positifs et 50 exemples négatifs sont créés. Cet échantillonnage est effectué sans pondération pour traiter des données déséquilibrées.) Il semble que cela s'appelle Balanced Random Forest. Dans R, il peut être facilement exécuté avec des paramètres, mais dans scikit-learn, il n'y en avait pas de correspondant, alors je l'ai essayé moi-même. (Si vous faites une erreur, veuillez commenter)

la mise en oeuvre

balanced_random_forest.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-

from collections import Counter
from random import sample
from math import sqrt
import numpy as np
import pandas as pd
from sklearn.tree import DecisionTreeClassifier
from sklearn.externals.joblib import Parallel, delayed
from sklearn.utils import resample


def _build_tree(train: np.ndarray, label: np.ndarray):
    tree = DecisionTreeClassifier()
    tree.fit(train, label)
    return tree


def _sampling_equal(y_values: np.ndarray, n_samples: int, bootstrap: bool = True):
    """
    :param y_values: label data
    :param n_samples: number of samples
    :param bootstrap: whether bootstrap or not
    :return: sampling index
    """
    if bootstrap:
        return [i for v in [resample(pd.Series(y_values)[pd.Series(y_values) == uq].index,
                                     n_samples=n_samples) for uq in np.unique(y_values)] for i in v]
    else:
        return [i for v in [sample(list(pd.Series(y_values)[pd.Series(y_values) == uq].index),
                                   n_samples) for uq in np.unique(y_values)] for i in v]


class BalancedRandomForestClassifier():
    """Prend en charge les données déséquilibrées en créant un arbre avec un nombre constant d'échantillons pour chaque classe"""

    def __init__(self, n_estimator: int, n_samples: int, bootstrap: bool = True, max_features: int = 0):
        """
        :param n_estimator: number of tree
        :param n_samples: number of sampling data
        :param bootstrap: how to resample
        :param max_features: number of feature
        """
        self.n_estimator = n_estimator
        self.n_samples = n_samples
        self.bootstrap = bootstrap
        self.max_features = max_features

    def fit(self, x_values: np.ndarray, y_values: np.ndarray):
        """
        :param x_values: train data
        :param y_values: label data
        """
        if self.max_features == 0:
            self.max_features = round(sqrt(x_values.shape[1]))
        #Sélectionnez les données à entraîner par l'arborescence avec bootstrap etc.
        index_list = [_sampling_equal(y_values, self.n_samples, self.bootstrap) for i in range(0, self.n_estimator)]
        #Sélectionnez le montant de la fonctionnalité pour chaque arbre
        self.feature_list = [sample(range(0, x_values.shape[1]), self.max_features) for i in range(0, self.n_estimator)]
        #Construisez un arbre basé sur ce qui précède
        self.forest = Parallel(n_jobs=-1, backend="threading")(
            delayed(_build_tree)(x_values[np.ix_(index, feature)], y_values[index])
            for index, feature in zip(index_list, self.feature_list))
        #Déterminé par la majorité des prédictions pour chaque arbre
        self.predict = lambda x: [Counter(item).most_common(1)[0][0]
                                  for item in np.array([tree.predict(x[:, feature])
                                                        for tree, feature in zip(self.forest, self.feature_list)]).T]
        #De là, le calcul de l'importance
        count = np.zeros(x_values.shape[1])
        feature_importances = np.zeros(x_values.shape[1])
        for tree, feature in zip(self.forest, self.feature_list):
            count[feature] += 1
            feature_importances[feature] += tree.feature_importances_
        self.feature_importances_ = feature_importances / count

Implémentation de l'arbre de décision de base

def _build_tree(train: np.ndarray, label: np.ndarray):
    tree = DecisionTreeClassifier()
    tree.fit(train, label)
    return tree

Il s'agit de l'arbre de décision scikit-learn tel quel. Balanced Random Forest ne modifie que la méthode d'échantillonnage, donc Il ne fait aucun doute que vous devriez en utiliser (ma puissance de montage est de 53)

Échantillonnage avec Bootstrap

def _sampling_equal(y_values: np.ndarray, n_samples: int, bootstrap: bool = True):
    """
    :param y_values: label data
    :param n_samples: number of samples
    :param bootstrap: whether bootstrap or not
    :return: sampling index
    """
    if bootstrap:
        return [i for v in [resample(pd.Series(y_values)[pd.Series(y_values) == uq].index,
                                     n_samples=n_samples) for uq in np.unique(y_values)] for i in v]
    else:
        return [i for v in [sample(list(pd.Series(y_values)[pd.Series(y_values) == uq].index),
                                   n_samples) for uq in np.unique(y_values)] for i in v]

Il obtient le même nombre d'étiquettes pour chaque étiquette avec un bootstrap (éventuellement échantillonnage sans duplication, mais généralement non utilisé). La raison pour laquelle cette inclusion est si ennuyeuse est que si vous échantillonnez chaque étiquette, ce sera un tableau multidimensionnel, donc pour le convertir en un tableau unidimensionnel

Apprentissage

def fit(self, x_values: np.ndarray, y_values: np.ndarray):
        """
        :param x_values: train data
        :param y_values: label data
        """
        if self.max_features == 0:
            self.max_features = round(sqrt(x_values.shape[1]))
        #Sélectionnez les données à entraîner par l'arborescence avec bootstrap etc.
        index_list = [_sampling_equal(y_values, self.n_samples, self.bootstrap) for i in range(0, self.n_estimator)]
        #Sélectionnez le montant de la fonctionnalité pour chaque arbre
        self.feature_list = [sample(range(0, x_values.shape[1]), self.max_features) for i in range(0, self.n_estimator)]
        #Construisez un arbre basé sur ce qui précède
        self.forest = Parallel(n_jobs=-1, backend="threading")(
            delayed(_build_tree)(x_values[np.ix_(index, feature)], y_values[index])
            for index, feature in zip(index_list, self.feature_list))
        #Déterminé par la majorité des prédictions pour chaque arbre
        self.predict = lambda x: [Counter(item).most_common(1)[0][0]
                                  for item in np.array([tree.predict(x[:, feature])
                                                        for tree, feature in zip(self.forest, self.feature_list)]).T]
        #De là, le calcul de l'importance
        count = np.zeros(x_values.shape[1])
        feature_importances = np.zeros(x_values.shape[1])
        for tree, feature in zip(self.forest, self.feature_list):
            count[feature] += 1
            feature_importances[feature] += tree.feature_importances_
        self.feature_importances_ = feature_importances / count

―― Tout d'abord, décidez du nombre de fonctionnalités à utiliser pour chaque arbre de décision

Puisque la valeur prédite est déterminée par la majorité des arbres créés, la prédiction est faite en fonction de la quantité de caractéristiques ( self.feature_list '') utilisée pour chaque arbre, et la majorité est prise ( Counter (item) .most_common. (1) [0] [0] `` a acquis les étiquettes les plus nombreuses.)

Puisque l'importance est calculée comme la valeur moyenne du taux de contribution du montant de la caractéristique pour chaque arbre déterminé, La valeur totale d'importance de chaque entité est divisée par le nombre d'occurrences.

Recommended Posts

Forêt aléatoire équilibrée en python
Utiliser Random Forest avec Python
Marche aléatoire en Python
Classification des maladies par Random Forest en utilisant Python
Choix aléatoire pondéré en python
Forêt aléatoire (2)
Forêt aléatoire
Tester avec des nombres aléatoires en Python
Créer une chaîne aléatoire en Python
Quadtree en Python --2
Python en optimisation
CURL en Python
Métaprogrammation avec Python
Python 3.3 avec Anaconda
Géocodage en python
SendKeys en Python
Méta-analyse en Python
Unittest en Python
Époque en Python
Discord en Python
Allemand en Python
DCI en Python
tri rapide en python
nCr en python
N-Gram en Python
Programmation avec Python
Plink en Python
Constante en Python
FizzBuzz en Python
Sqlite en Python
Étape AIC en Python
LINE-Bot [0] en Python
CSV en Python
Assemblage inversé avec Python
Réflexion en Python
Constante en Python
nCr en Python.
format en python
Scons en Python 3
Puyopuyo en python
python dans virtualenv
PPAP en Python
Quad-tree en Python
Réflexion en Python
Chimie avec Python
Hashable en Python
DirectLiNGAM en Python
[Python] Classification des maladies dans une forêt aléatoire-avec LDA-
LiNGAM en Python
Aplatir en Python
Aplatir en python
Méthodes de test qui renvoient des valeurs aléatoires en Python
Liste triée en Python
Texte de cluster en Python
AtCoder # 2 tous les jours avec Python
Daily AtCoder # 6 en Python
Daily AtCoder # 18 en Python
Modifier les polices en Python