Élimination de fonctions récursives sur la forêt aléatoire à l'aide de scikit-learn
j'essaie de préformer l'élimination des fonctions récursives en utilisant scikit-learn
et un classificateur de forêt aléatoire, avec OOB ROC comme méthode de notation de chaque sous-ensemble créé pendant le processus récursif.
cependant, quand j'essaie d'utiliser la méthode RFECV
, j'obtiens une erreur disant AttributeError: 'RandomForestClassifier' object has no attribute 'coef_'
les forêts aléatoires n'ont pas de coefficients en soi, mais elles ont des classements par score de Gini. Donc, je me demandais comment obtenir autour de ce problème.
s'il vous plaît noter que je veux utiliser une méthode qui me dira explicitement quelles fonctionnalités de mon datagramme pandas
ont été sélectionnées dans le groupe optimal car j'utilise la sélection de fonctionnalités récursives pour essayer de minimiser la quantité de données que je vais entrer dans le classificateur final.
voici un exemple de code:
from sklearn import datasets
import pandas as pd
from pandas import Series
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import RFECV
iris = datasets.load_iris()
x=pd.DataFrame(iris.data, columns=['var1','var2','var3', 'var4'])
y=pd.Series(iris.target, name='target')
rf = RandomForestClassifier(n_estimators=500, min_samples_leaf=5, n_jobs=-1)
rfecv = RFECV(estimator=rf, step=1, cv=10, scoring='ROC', verbose=2)
selector=rfecv.fit(x, y)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/feature_selection/rfe.py", line 336, in fit
ranking_ = rfe.fit(X_train, y_train).ranking_
File "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/feature_selection/rfe.py", line 148, in fit
if estimator.coef_.ndim > 1:
AttributeError: 'RandomForestClassifier' object has no attribute 'coef_'
4 réponses
voici ce que j'ai fait pour adapter RandomForestClassifier pour travailler avec RFECV:
class RandomForestClassifierWithCoef(RandomForestClassifier):
def fit(self, *args, **kwargs):
super(RandomForestClassifierWithCoef, self).fit(*args, **kwargs)
self.coef_ = self.feature_importances_
L'utilisation de cette classe suffit si vous utilisez 'accuracy' ou 'f1' score. Pour' roc_auc', RFECV se plaint que le format multiclasse n'est pas supporté. En changeant la classification à deux classes avec le code ci-dessous, la notation "roc_auc" fonctionne. (Utilisant Python 3.4.1 et scikit-learn 0.15.1)
y=(pd.Series(iris.target, name='target')==2).astype(int)
brancher votre code:
from sklearn import datasets
import pandas as pd
from pandas import Series
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import RFECV
class RandomForestClassifierWithCoef(RandomForestClassifier):
def fit(self, *args, **kwargs):
super(RandomForestClassifierWithCoef, self).fit(*args, **kwargs)
self.coef_ = self.feature_importances_
iris = datasets.load_iris()
x=pd.DataFrame(iris.data, columns=['var1','var2','var3', 'var4'])
y=(pd.Series(iris.target, name='target')==2).astype(int)
rf = RandomForestClassifierWithCoef(n_estimators=500, min_samples_leaf=5, n_jobs=-1)
rfecv = RFECV(estimator=rf, step=1, cv=2, scoring='roc_auc', verbose=2)
selector=rfecv.fit(x, y)
C'est mon code, je l'ai rangé un peu pour le rendre pertinent à votre tâche:
features_to_use = fea_cols # this is a list of features
# empty dataframe
trim_5_df = DataFrame(columns=features_to_use)
run=1
# this will remove the 5 worst features determined by their feature importance computed by the RF classifier
while len(features_to_use)>6:
print('number of features:%d' % (len(features_to_use)))
# build the classifier
clf = RandomForestClassifier(n_estimators=1000, random_state=0, n_jobs=-1)
# train the classifier
clf.fit(train[features_to_use], train['OpenStatusMod'].values)
print('classifier score: %f\n' % clf.score(train[features_to_use], df['OpenStatusMod'].values))
# predict the class and print the classification report, f1 micro, f1 macro score
pred = clf.predict(test[features_to_use])
print(classification_report(test['OpenStatusMod'].values, pred, target_names=status_labels))
print('micro score: ')
print(metrics.precision_recall_fscore_support(test['OpenStatusMod'].values, pred, average='micro'))
print('macro score:\n')
print(metrics.precision_recall_fscore_support(test['OpenStatusMod'].values, pred, average='macro'))
# predict the class probabilities
probs = clf.predict_proba(test[features_to_use])
# rescale the priors
new_probs = kf.cap_and_update_priors(priors, probs, private_priors, 0.001)
# calculate logloss with the rescaled probabilities
print('log loss: %f\n' % log_loss(test['OpenStatusMod'].values, new_probs))
row={}
if hasattr(clf, "feature_importances_"):
# sort the features by importance
sorted_idx = np.argsort(clf.feature_importances_)
# reverse the order so it is descending
sorted_idx = sorted_idx[::-1]
# add to dataframe
row['num_features'] = len(features_to_use)
row['features_used'] = ','.join(features_to_use)
# trim the worst 5
sorted_idx = sorted_idx[: -5]
# swap the features list with the trimmed features
temp = features_to_use
features_to_use=[]
for feat in sorted_idx:
features_to_use.append(temp[feat])
# add the logloss performance
row['logloss']=[log_loss(test['OpenStatusMod'].values, new_probs)]
print('')
# add the row to the dataframe
trim_5_df = trim_5_df.append(DataFrame(row))
run +=1
donc ce que je fais ici est que j'ai une liste de fonctionnalités que je veux former et ensuite prédire contre, en utilisant les importances de fonctionnalités, je puis couper les 5 pires et répéter. Pendant chaque exécution, j'ajoute une rangée pour enregistrer la performance de prédiction afin que je puisse faire une analyse plus tard.
le code original était beaucoup plus grand j'avais différents classificateurs et ensembles de données I j'étais en train d'analyser mais j'espère que vous obtiendrez la photo ci-dessus. Ce que j'ai remarqué, c'est que pour random forest, le nombre de caractéristiques que j'ai enlevées à chaque course a affecté la performance, de sorte que le découpage par 1, 3 et 5 caractéristiques à la fois a donné lieu à un ensemble différent de meilleures caractéristiques.
j'ai trouvé que l'utilisation d'un classificateur de pente était plus prévisible et reproductible dans le sens que l'ensemble final des meilleures caractéristiques convenu si j'ai coupé 1 caractéristique à la fois ou 3 ou 5.
j'espère que je ne vous apprends pas à sucer des œufs ici, vous en savez probablement plus que moi, mais mon approche à l'anlaysis a été d'utiliser un classificateur rapide pour obtenir une idée approximative des meilleurs ensembles de caractéristiques, puis utiliser un classificateur plus performant, puis commencer à l'ajustement des paramètres hyper, de nouveau faire des comaprisons à grain grossier et ensuite grain fin une fois que j'ai une idée de ce que les meilleurs params étaient.
j'ai soumis une demande pour ajouter coef_
afin que RandomForestClassifier
puisse être utilisé avec RFECV
. Cependant, le changement a déjà été fait. Ce changement sera dans la version 0.17.
https://github.com/scikit-learn/scikit-learn/issues/4945
Vous pouvez tirer la dernière dev build si vous voulez l'utiliser maintenant.
voilà ce que j'ai préparé. C'est une solution assez simple, et repose sur une métrique de précision personnalisée (appelée pesedaccuracy) puisque je classe un ensemble de données très déséquilibré. Mais, il devrait être facilement rendu plus extensible si vous le souhaitez.
from sklearn import datasets
import pandas
from sklearn.ensemble import RandomForestClassifier
from sklearn import cross_validation
from sklearn.metrics import confusion_matrix
def get_enhanced_confusion_matrix(actuals, predictions, labels):
""""enhances confusion_matrix by adding sensivity and specificity metrics"""
cm = confusion_matrix(actuals, predictions, labels = labels)
sensitivity = float(cm[1][1]) / float(cm[1][0]+cm[1][1])
specificity = float(cm[0][0]) / float(cm[0][0]+cm[0][1])
weightedAccuracy = (sensitivity * 0.9) + (specificity * 0.1)
return cm, sensitivity, specificity, weightedAccuracy
iris = datasets.load_iris()
x=pandas.DataFrame(iris.data, columns=['var1','var2','var3', 'var4'])
y=pandas.Series(iris.target, name='target')
response, _ = pandas.factorize(y)
xTrain, xTest, yTrain, yTest = cross_validation.train_test_split(x, response, test_size = .25, random_state = 36583)
print "building the first forest"
rf = RandomForestClassifier(n_estimators = 500, min_samples_split = 2, n_jobs = -1, verbose = 1)
rf.fit(xTrain, yTrain)
importances = pandas.DataFrame({'name':x.columns,'imp':rf.feature_importances_
}).sort(['imp'], ascending = False).reset_index(drop = True)
cm, sensitivity, specificity, weightedAccuracy = get_enhanced_confusion_matrix(yTest, rf.predict(xTest), [0,1])
numFeatures = len(x.columns)
rfeMatrix = pandas.DataFrame({'numFeatures':[numFeatures],
'weightedAccuracy':[weightedAccuracy],
'sensitivity':[sensitivity],
'specificity':[specificity]})
print "running RFE on %d features"%numFeatures
for i in range(1,numFeatures,1):
varsUsed = importances['name'][0:i]
print "now using %d of %s features"%(len(varsUsed), numFeatures)
xTrain, xTest, yTrain, yTest = cross_validation.train_test_split(x[varsUsed], response, test_size = .25)
rf = RandomForestClassifier(n_estimators = 500, min_samples_split = 2,
n_jobs = -1, verbose = 1)
rf.fit(xTrain, yTrain)
cm, sensitivity, specificity, weightedAccuracy = get_enhanced_confusion_matrix(yTest, rf.predict(xTest), [0,1])
print("\n"+str(cm))
print('the sensitivity is %d percent'%(sensitivity * 100))
print('the specificity is %d percent'%(specificity * 100))
print('the weighted accuracy is %d percent'%(weightedAccuracy * 100))
rfeMatrix = rfeMatrix.append(
pandas.DataFrame({'numFeatures':[len(varsUsed)],
'weightedAccuracy':[weightedAccuracy],
'sensitivity':[sensitivity],
'specificity':[specificity]}), ignore_index = True)
print("\n"+str(rfeMatrix))
maxAccuracy = rfeMatrix.weightedAccuracy.max()
maxAccuracyFeatures = min(rfeMatrix.numFeatures[rfeMatrix.weightedAccuracy == maxAccuracy])
featuresUsed = importances['name'][0:maxAccuracyFeatures].tolist()
print "the final features used are %s"%featuresUsed