2014-06-09 2 views
14

Я пытаюсь выполнить рекурсивное исключение функции с помощью scikit-learn и случайного классификатора леса, с OOB ROC как метод подсчета каждого подмножества, созданного во время рекурсивного процесса.Рекурсивное устранение функции в случайном лесу с использованием scikit-learn

Однако, когда я пытаюсь использовать метод RFECV, я получаю сообщение об ошибке говорящее AttributeError: 'RandomForestClassifier' object has no attribute 'coef_'

Случайные леса не имеют коэффициенты сами по себе, но они имеют рейтинг от Джини балла. Итак, мне интересно, как решить эту проблему.

Обратите внимание, что я хочу использовать метод, который будет явно указывать мне, какие функции из моего pandas DataFrame были выбраны в оптимальной группировке, поскольку я использую рекурсивную функцию, чтобы попытаться свести к минимуму количество данных, которые я буду вводить в окончательный классификатор.

Вот пример кода:

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_' 
+1

Альтернативный подход заключается в использовании атрибута 'feature_importances_' после вызова' pred' или 'pred_proba', это возвращает массив процентов в том порядке, в котором они были переданы. См. [Онлайн-пример] (http://scikit-learn.org/stable/auto_examples/ensemble/plot_gradient_boosting_regression.html) – EdChum

+0

Видел это; Я хочу знать, есть ли что-то, что позволяет мне в 10 раз проверить и определить оптимальное подмножество функций. – Bryan

+0

Мне пришлось сделать что-то подобное, но я сделал это вручную, сортируя функции, а затем обрезая по 1,3 или 5 штук за раз. Я не использовал ваш подход, я должен сказать, поэтому я не знаю, можно ли это сделать. – EdChum

ответ

3

Вот что я сделал. Это довольно простое решение, и полагается на пользовательскую метрику точности (называемую weightedAccuracy), так как я классифицирую очень неуравновешенный набор данных. Но при желании его легко сделать более растяжимым.

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 
6

Это мой код, я убирала его немного, чтобы сделать его отношение к вашей задаче:

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 

Итак, что я делаю вот у меня есть список функций, которые я хочу тренировать, а затем прогнозирую против, используя особенности, которые я потом обрезаю худшим 5 и повторяю. Во время каждого прогона я добавляю строку, чтобы записать производительность прогнозирования, чтобы позже я смог сделать некоторый анализ.

Исходный код был намного больше У меня были разные классификаторы и наборы данных, которые я анализировал, но я надеюсь, что вы получите картину из вышеперечисленного. То, что я заметил, было то, что для случайного леса количество функций, которые я удалял при каждом запуске, повлияло на производительность, поэтому обрезка по 1, 3 и 5 функциям за один раз привела к другому набору лучших функций.

Я обнаружил, что использование GradientBoostingClassifer было более предсказуемым и воспроизводимым в том смысле, что конечный набор лучших черт согласились обрезан ли я 1 функция в то время, или 3 или 5.

Я надеюсь, что я не учу вы, возможно, знаете, что вы, возможно, знаете больше, чем я, но мой подход к абляционному anlaysis состоял в том, чтобы использовать быстрый классификатор, чтобы получить приблизительное представление о лучших наборах функций, затем использовать более эффективный классификатор, затем начать настройку гиперпараметров, снова делаю грубые зерновые компризоны, а затем мелкое зерно, как только я получу представление о том, какие лучшие параметры были.

17

Вот что я сделал, чтобы адаптировать RandomForestClassifier работать с RFECV:

class RandomForestClassifierWithCoef(RandomForestClassifier): 
    def fit(self, *args, **kwargs): 
     super(RandomForestClassifierWithCoef, self).fit(*args, **kwargs) 
     self.coef_ = self.feature_importances_ 

Только с помощью этого класса делает трюк, если вы используете «точность» или оценка «F1». Для «roc_auc» RFECV жалуется, что формат многоклассов не поддерживается. Изменяя его на двухклассную классификацию с приведенным ниже кодом, работает скоринг «roc_auc». (Использование Python 3.4.1 и scikit-learn 0.15.1)

y=(pd.Series(iris.target, name='target')==2).astype(int) 

Подключив в код:

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

Я подал запрос на добавление coef_ так RandomForestClassifier могут быть использованы с RFECV. Однако это изменение уже было сделано. Это изменение будет в версии 0.17.

https://github.com/scikit-learn/scikit-learn/issues/4945

Вы можете вытащить последний DEV строить, если вы хотите использовать его сейчас.

Смежные вопросы