Balanced Random Forest in Python

Über Random Forest

Random Forest ist ein Gruppenlernalgorithmus, der einen Entscheidungsbaum als schwache Lernmaschine verwendet und eine der typischen Methoden des maschinellen Lernens ist. Wir werden einen Entscheidungsbaum erstellen, indem wir Merkmalsmengen und Beobachtungsdaten abtasten. Wenn Sie nachschlagen, werden Sie viel finden, daher werde ich die Algorithmen hier weglassen.

Probleme bei unausgeglichenen Daten

Wenn Sie beispielsweise versuchen, die Daten von 1000 positiven und 50 negativen Fällen nach Random Forest zu klassifizieren, können Sie sie nur dann als Klassifizierer verwenden, wenn Sie bestimmte Maßnahmen ergreifen. Es kann auch durch Gewichtung der unausgeglichenen Daten behandelt werden (einstellbar als class_weight-Parameter für RandomForest in scikit-learn). Es ist jedoch möglich, dass das Gewicht eines Datums zu stark ist und ein Übertraining auftreten kann.

Was ist Balanced Random Forest?

Daher gibt es eine Methode zum Umgang mit unausgeglichenen Daten durch Anpassen der Anzahl von Stichproben für jeden Entscheidungsbaum. (Im vorherigen Beispiel werden beispielsweise für jeden Entscheidungsbaum 50 positive und 50 negative Beispiele erstellt. Eine solche Stichprobe wird ohne Gewichtung durchgeführt, um mit unausgeglichenen Daten umzugehen.) Es scheint, dass dies Balanced Random Forest genannt wird. In R kann es leicht mit Parametern ausgeführt werden, aber in scikit-learn gab es keinen entsprechenden, also habe ich es selbst versucht, obwohl es einfach war. (Wenn Sie einen Fehler machen, kommentieren Sie bitte)

Implementierung

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():
    """Unterstützt unausgeglichene Daten, indem für jede Klasse ein Baum mit einer konstanten Anzahl von Stichproben erstellt wird"""

    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]))
        #Wählen Sie die Daten aus, die vom Baum mit Bootstrap usw. trainiert werden sollen.
        index_list = [_sampling_equal(y_values, self.n_samples, self.bootstrap) for i in range(0, self.n_estimator)]
        #Wählen Sie den Funktionsbetrag für jeden Baum aus
        self.feature_list = [sample(range(0, x_values.shape[1]), self.max_features) for i in range(0, self.n_estimator)]
        #Erstellen Sie einen Baum basierend auf den oben genannten
        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))
        #Bestimmt durch die Mehrheit der Vorhersagen für jeden Baum
        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]
        #Ab hier die Wichtigkeitsberechnung
        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

Implementierung des Basisentscheidungsbaums

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

Dies ist der Scikit-Learn-Entscheidungsbaum, wie er ist. Balanced Random Forest ändert also nur die Stichprobenmethode Es besteht kein Zweifel, dass Sie einige verwenden sollten (meine Montageleistung beträgt 53)

Sampling mit 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]

Es erhält die gleiche Anzahl von Etiketten für jedes Etikett mit einem Bootstrap (optional ohne Duplizierung, aber normalerweise nicht verwendet). Der Grund, warum es so ärgerlich ist, ist, dass wenn Sie jedes Etikett abtasten, es ein mehrdimensionales Array ist, um es in ein eindimensionales Array umzuwandeln

Lernen

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]))
        #Wählen Sie die Daten aus, die vom Baum mit Bootstrap usw. trainiert werden sollen.
        index_list = [_sampling_equal(y_values, self.n_samples, self.bootstrap) for i in range(0, self.n_estimator)]
        #Wählen Sie den Funktionsbetrag für jeden Baum aus
        self.feature_list = [sample(range(0, x_values.shape[1]), self.max_features) for i in range(0, self.n_estimator)]
        #Erstellen Sie einen Baum basierend auf den oben genannten
        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))
        #Bestimmt durch die Mehrheit der Vorhersagen für jeden Baum
        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]
        #Ab hier die Wichtigkeitsberechnung
        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

Da der vorhergesagte Wert von der Mehrheit der erstellten Bäume bestimmt wird, wird die Vorhersage basierend auf der für jeden Baum verwendeten Merkmalsmenge ( self.feature_list) gemacht, und die Mehrheit wird genommen (Counter (item) .most_common. (1) [0] [0] hat die zahlreichsten Labels erworben.)

Da die Wichtigkeit als Durchschnittswert des Beitragssatzes des Merkmalsbetrags für jeden bestimmten Baum berechnet wird, Der Gesamtwert der Wichtigkeit für jedes Merkmal wird durch die Anzahl der Vorkommen geteilt.

Recommended Posts

Balanced Random Forest in Python
Verwenden Sie Random Forest mit Python
Zufälliger Spaziergang in Python
Krankheitsklassifizierung durch Random Forest mit Python
Gewichtete zufällige Auswahl in Python
Zufälliger Wald (2)
Zufälliger Wald
Testen mit Zufallszahlen in Python
Erstellen Sie eine zufällige Zeichenfolge in Python
Quadtree in Python --2
Python in der Optimierung
CURL in Python
Metaprogrammierung mit Python
Python 3.3 mit Anaconda
Geokodierung in Python
SendKeys in Python
Metaanalyse in Python
Unittest in Python
Epoche in Python
Zwietracht in Python
Deutsch in Python
DCI in Python
Quicksort in Python
nCr in Python
N-Gramm in Python
Programmieren mit Python
Plink in Python
Konstante in Python
FizzBuzz in Python
SQLite in Python
Schritt AIC in Python
LINE-Bot [0] in Python
CSV in Python
Reverse Assembler mit Python
Reflexion in Python
Konstante in Python
nCr in Python.
Format in Python
Scons in Python 3
Puyopuyo in Python
Python in Virtualenv
PPAP in Python
Quad-Tree in Python
Reflexion in Python
Chemie mit Python
Hashbar in Python
DirectLiNGAM in Python
[Python] Krankheitsklassifikation in zufälligen Wäldern - mit LDA-
LiNGAM in Python
In Python reduzieren
In Python flach drücken
Testmethoden, die zufällige Werte in Python zurückgeben
Sortierte Liste in Python
Clustertext in Python
AtCoder # 2 jeden Tag mit Python
Täglicher AtCoder # 6 in Python
Täglicher AtCoder # 18 in Python
Bearbeiten Sie Schriftarten in Python