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.
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.
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)
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
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)
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
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