Puisque lightGBM et xgboost ne fonctionnaient pas dans Boruta, j'ai réécrit une partie pour que cela fonctionne.
Voir ci-dessous pour savoir comment le faire normalement avec l'estimateur sklearn https://qiita.com/studio_haneya/items/bdb25b19baaf43d867d7
Windows10 python 3.6.7 scikit-learn 0.21.3 lightgbm 2.3.0 xgboost 0.90
Boruta fonctionne avec l'estimateur sklearn qui peut obtenir feature_importance_, vous pouvez donc utiliser RandomForest et GradientBoosting, mais le wrapper sklearn de lightGBM et xgboost ressemble à sklearn, mais il ne fonctionne pas tel quel car il est un peu différent. est. Donc, j'ai hérité de la classe BorutaPy et je l'ai réécrit en partie pour la faire fonctionner.
Il existe deux différences qui peuvent être problématiques lorsque vous essayez d'utiliser lightGBM avec Boruta:
boruta | lgb/xgb | |
---|---|---|
random_state | np.random.RandomState | int |
max_Aucune limite de profondeur | None | -1 |
Dans sklearn, la valeur de départ peut être transmise par np.random.RandomState (), mais lightGBM / xgboost ne peut pas la passer en tant que valeur numérique de type int, et elle est affectée aux paramètres lorsque la limite max_depth est supprimée. Comme la valeur est None pour sklearn et -1 pour lightGBM, n_estimators calculés en fonction de max_depth ne peuvent pas être calculés normalement. Donc, si vous corrigez les pièces qui correspondent à ces deux, cela fonctionnera.
Voici l'exemple de code qui exécute lightGBM. J'ai hérité de BorutaPy et je l'ai réécrit en partie, mais comme _fit () est conçu pour remplacer random_state par np.random.RandomState () puis self.estimator.fit (), il n'est pas réécrit. Je ne peux pas penser à un moyen de le faire, et c'est un code très long. S'il vous plaît laissez-moi savoir s'il existe une meilleure façon. (Corrigé 20191102: Corrigé car le code ne reflétait pas la valeur de l'état aléatoire) </ font>
python
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, accuracy_score
from boruta import BorutaPy
import lightgbm as lgb
import xgboost as xgb
from sklearn.utils import check_random_state
class BorutaPyForLGB(BorutaPy):
def __init__(self, estimator, n_estimators=1000, perc=100, alpha=0.05,
two_step=True, max_iter=100, random_state=None, verbose=0):
super().__init__(estimator, n_estimators, perc, alpha,
two_step, max_iter, random_state, verbose)
if random_state is None:
self.random_state_input = np.random.randint(0, 2**64-1)
elif isinstance(random_state, int):
self.random_state_input = random_state
else:
raise TypeError('random_state must be int or None')
def _get_tree_num(self, n_feat):
depth = self.estimator.get_params()['max_depth']
if (depth == None) or (depth <= 0):
depth = 10
f_repr = 100
multi = ((n_feat * 2) / (np.sqrt(n_feat * 2) * depth))
n_estimators = int(multi * f_repr)
return n_estimators
def _fit(self, X, y):
# check input params
self._check_params(X, y)
self.random_state = check_random_state(self.random_state)
# setup variables for Boruta
n_sample, n_feat = X.shape
_iter = 1
# holds the decision about each feature:
# 0 - default state = tentative in original code
# 1 - accepted in original code
# -1 - rejected in original code
dec_reg = np.zeros(n_feat, dtype=np.int)
# counts how many times a given feature was more important than
# the best of the shadow features
hit_reg = np.zeros(n_feat, dtype=np.int)
# these record the history of the iterations
imp_history = np.zeros(n_feat, dtype=np.float)
sha_max_history = []
# set n_estimators
if self.n_estimators != 'auto':
self.estimator.set_params(n_estimators=self.n_estimators)
# main feature selection loop
while np.any(dec_reg == 0) and _iter < self.max_iter:
# find optimal number of trees and depth
if self.n_estimators == 'auto':
# number of features that aren't rejected
not_rejected = np.where(dec_reg >= 0)[0].shape[0]
n_tree = self._get_tree_num(not_rejected)
self.estimator.set_params(n_estimators=n_tree)
# make sure we start with a new tree in each iteration
self.estimator.set_params(random_state=self.random_state_input)
# add shadow attributes, shuffle them and train estimator, get imps
cur_imp = self._add_shadows_get_imps(X, y, dec_reg)
# get the threshold of shadow importances we will use for rejection
imp_sha_max = np.percentile(cur_imp[1], self.perc)
# record importance history
sha_max_history.append(imp_sha_max)
imp_history = np.vstack((imp_history, cur_imp[0]))
# register which feature is more imp than the max of shadows
hit_reg = self._assign_hits(hit_reg, cur_imp, imp_sha_max)
# based on hit_reg we check if a feature is doing better than
# expected by chance
dec_reg = self._do_tests(dec_reg, hit_reg, _iter)
# print out confirmed features
if self.verbose > 0 and _iter < self.max_iter:
self._print_results(dec_reg, _iter, 0)
if _iter < self.max_iter:
_iter += 1
# we automatically apply R package's rough fix for tentative ones
confirmed = np.where(dec_reg == 1)[0]
tentative = np.where(dec_reg == 0)[0]
# ignore the first row of zeros
tentative_median = np.median(imp_history[1:, tentative], axis=0)
# which tentative to keep
tentative_confirmed = np.where(tentative_median
> np.median(sha_max_history))[0]
tentative = tentative[tentative_confirmed]
# basic result variables
self.n_features_ = confirmed.shape[0]
self.support_ = np.zeros(n_feat, dtype=np.bool)
self.support_[confirmed] = 1
self.support_weak_ = np.zeros(n_feat, dtype=np.bool)
self.support_weak_[tentative] = 1
# ranking, confirmed variables are rank 1
self.ranking_ = np.ones(n_feat, dtype=np.int)
# tentative variables are rank 2
self.ranking_[tentative] = 2
# selected = confirmed and tentative
selected = np.hstack((confirmed, tentative))
# all rejected features are sorted by importance history
not_selected = np.setdiff1d(np.arange(n_feat), selected)
# large importance values should rank higher = lower ranks -> *(-1)
imp_history_rejected = imp_history[1:, not_selected] * -1
# update rank for not_selected features
if not_selected.shape[0] > 0:
# calculate ranks in each iteration, then median of ranks across feats
iter_ranks = self._nanrankdata(imp_history_rejected, axis=1)
rank_medians = np.nanmedian(iter_ranks, axis=0)
ranks = self._nanrankdata(rank_medians, axis=0)
# set smallest rank to 3 if there are tentative feats
if tentative.shape[0] > 0:
ranks = ranks - np.min(ranks) + 3
else:
# and 2 otherwise
ranks = ranks - np.min(ranks) + 2
self.ranking_[not_selected] = ranks
else:
# all are selected, thus we set feature supports to True
self.support_ = np.ones(n_feat, dtype=np.bool)
# notify user
if self.verbose > 0:
self._print_results(dec_reg, _iter, 1)
return self
Maintenant que nous sommes prêts, exécutons-le ci-dessous. Le code est basé sur ce qui suit. https://github.com/masakiaota/blog/blob/master/boruta/Madalon_Data_Set.ipynb
def main():
#Lisez les données
data_url='https://archive.ics.uci.edu/ml/machine-learning-databases/madelon/MADELON/madelon_train.data'
label_url='https://archive.ics.uci.edu/ml/machine-learning-databases/madelon/MADELON/madelon_train.labels'
X_data = pd.read_csv(data_url, sep=" ", header=None)
y_data = pd.read_csv(label_url, sep=" ", header=None)
data = X_data.iloc[:,0:500]
data['target'] = y_data[0]
y=data['target']
X=data.drop(columns='target')
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)
#Apprenez avec des données complètes
model = lgb.LGBMClassifier(objective='binary',
num_leaves = 23,
learning_rate=0.1,
n_estimators=100,)
model.fit(X_train.values, y_train.values)
y_test_pred = model.predict(X_test.values)
print(confusion_matrix(y_test.values, y_test_pred, labels=model.classes_), '\n')
print('SCORE with ALL Features: %1.2f\n' % accuracy_score(y_test, y_test_pred))
#Sélection de fonctionnalités avec Boruta(Utilisez le Boruta Py partiellement réécrit)
model = lgb.LGBMClassifier(objective='binary',
num_leaves = 23,
learning_rate=0.1,
n_estimators=100,)
feat_selector = BorutaPyForLGB(model, n_estimators='auto', two_step=False,verbose=2, random_state=42)
feat_selector.fit(X_train.values, y_train.values)
print(X_train.columns[feat_selector.support_])
#Extraire la fonction sélectionnée
X_train_selected = X_train.iloc[:,feat_selector.support_]
X_test_selected = X_test.iloc[:,feat_selector.support_]
print(X_test_selected.head())
#Apprenez avec la fonctionnalité sélectionnée
model = lgb.LGBMClassifier(objective='binary',
num_leaves = 23,
learning_rate=0.1,
n_estimators=100,)
model.fit(X_train_selected.values, y_train.values)
y_test_pred = model.predict(X_test_selected.values)
print(confusion_matrix(y_test.values, y_test_pred, labels=model.classes_), '\n')
print('SCORE with selected Features: %1.2f\n' % accuracy_score(y_test, y_test_pred))
if __name__=='__main__':
main()
Le résultat de son exécution est le suivant. Il semble que vous puissiez le sélectionner correctement.
résultat
[[192 57]
[ 49 202]]
SCORE with ALL Features: 0.79
Index([48, 105, 153, 241, 318, 336, 338, 378, 442, 453, 472, 475], dtype='object')
[[212 37]
[ 34 217]]
SCORE with selected Features: 0.86
BorutaPyForLGB () créé ci-dessus peut également être utilisé avec xgboost.
python
def main():
#Lisez les données
data_url='https://archive.ics.uci.edu/ml/machine-learning-databases/madelon/MADELON/madelon_train.data'
label_url='https://archive.ics.uci.edu/ml/machine-learning-databases/madelon/MADELON/madelon_train.labels'
X_data = pd.read_csv(data_url, sep=" ", header=None)
y_data = pd.read_csv(label_url, sep=" ", header=None)
data = X_data.iloc[:,0:500]
data['target'] = y_data[0]
y=data['target']
X=data.drop(columns='target')
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)
#Apprenez avec des données complètes
model = lgb.LGBMClassifier(objective='binary',
num_leaves = 23,
learning_rate=0.1,
n_estimators=100,)
model.fit(X_train.values, y_train.values)
y_test_pred = model.predict(X_test.values)
print(confusion_matrix(y_test.values, y_test_pred, labels=model.classes_), '\n')
print('SCORE with ALL Features: %1.2f\n' % accuracy_score(y_test, y_test_pred))
#Sélection de fonctionnalités avec Boruta(Utilisez le Boruta Py partiellement réécrit)
model = lgb.LGBMClassifier(objective='binary',
num_leaves = 23,
learning_rate=0.1,
n_estimators=100,)
feat_selector = BorutaPyForLGB(model, n_estimators='auto', two_step=False,verbose=2, random_state=42)
feat_selector.fit(X_train.values, y_train.values)
print(X_train.columns[feat_selector.support_])
#Extraire la fonction sélectionnée
X_train_selected = X_train.iloc[:,feat_selector.support_]
X_test_selected = X_test.iloc[:,feat_selector.support_]
print(X_test_selected.head())
#Apprenez avec la fonctionnalité sélectionnée
model = lgb.LGBMClassifier(objective='binary',
num_leaves = 23,
learning_rate=0.1,
n_estimators=100,)
model.fit(X_train_selected.values, y_train.values)
y_test_pred = model.predict(X_test_selected.values)
print(confusion_matrix(y_test.values, y_test_pred, labels=model.classes_), '\n')
print('SCORE with selected Features: %1.2f\n' % accuracy_score(y_test, y_test_pred))
if __name__=='__main__':
main()
Cela fonctionne, mais cela ne fonctionne pas bien et la précision a chuté. Il semble que le nombre de fonctionnalités ait été trop réduit, mais pourquoi?
résultat
[[182 67]
[ 75 176]]
SCORE with ALL Features: 0.72
Index([28, 378, 451, 475], dtype='object')
[[148 101]
[109 142]]
SCORE with selected Features: 0.58
C'est comme ça. S'il vous plaît laissez-moi savoir s'il existe un moyen de l'écrire plus court. Essayons!
Recommended Posts