É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_'
14
demandé sur Bryan 2014-06-09 19:26:35

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)
19
répondu A.P. 2014-08-22 19:14:15

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.

5
répondu EdChum 2014-06-10 08:26:35

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.

4
répondu Dale Smith 2015-07-10 12:30:45

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
3
répondu Bryan 2014-07-09 17:52:14