web-dev-qa-db-fra.com

Comment obtenir les fonctionnalités les plus informatives pour les classificateurs scikit-learn?

Les classificateurs dans les packages d'apprentissage machine tels que liblinear et nltk proposent une méthode show_most_informative_features(), ce qui est très utile pour les fonctionnalités de débogage:

viagra = None          ok : spam     =      4.5 : 1.0
hello = True           ok : spam     =      4.5 : 1.0
hello = None           spam : ok     =      3.3 : 1.0
viagra = True          spam : ok     =      3.3 : 1.0
casino = True          spam : ok     =      2.0 : 1.0
casino = None          ok : spam     =      1.5 : 1.0

Ma question est de savoir si quelque chose de similaire est implémenté pour les classificateurs dans scikit-learn. J'ai cherché dans la documentation, mais je n'ai rien trouvé de semblable.

Si cette fonction n'existe pas encore, est-ce que quelqu'un connaît une solution de contournement pour accéder à ces valeurs?

Merci beaucoup!

60
tobigue

Avec l'aide du code larsmans, j'ai créé ce code pour le cas binaire:

def show_most_informative_features(vectorizer, clf, n=20):
    feature_names = vectorizer.get_feature_names()
    coefs_with_fns = sorted(Zip(clf.coef_[0], feature_names))
    top = Zip(coefs_with_fns[:n], coefs_with_fns[:-(n + 1):-1])
    for (coef_1, fn_1), (coef_2, fn_2) in top:
        print "\t%.4f\t%-15s\t\t%.4f\t%-15s" % (coef_1, fn_1, coef_2, fn_2)
45
tobigue

Les classificateurs eux-mêmes n'enregistrent pas les noms d'entités, ils ne voient que des tableaux numériques. Toutefois, si vous avez extrait vos entités à l'aide d'une variable VectorizerCountVectorizer/TfidfVectorizer/DictVectorizer, _/et, vous utilisez un modèle linéaire (par exemple, LinearSVC ou Naive Bayes), vous pouvez appliquer la même astuce que l'exemple de classification de document les usages. Exemple (untested, peut contenir un bogue ou deux):

def print_top10(vectorizer, clf, class_labels):
    """Prints features with the highest coefficient values, per class"""
    feature_names = vectorizer.get_feature_names()
    for i, class_label in enumerate(class_labels):
        top10 = np.argsort(clf.coef_[i])[-10:]
        print("%s: %s" % (class_label,
              " ".join(feature_names[j] for j in top10)))

Ceci est pour la classification multiclass; pour le cas binaire, je pense que vous devriez utiliser clf.coef_[0] uniquement. Vous devrez peut-être trier le class_labels.

56
Fred Foo

Pour ajouter une mise à jour, RandomForestClassifier prend désormais en charge l'attribut .feature_importances_. Cet attribut vous indique quelle part de la variance observée est expliquée par cette caractéristique. Évidemment, la somme de toutes ces valeurs doit être <= 1. 

Je trouve cet attribut très utile lors de l'ingénierie de fonctionnalités. 

Merci à l'équipe scikit-learn et aux contributeurs pour l'implémentation!

edit: Cela fonctionne à la fois pour RandomForest et GradientBoosting. Donc, RandomForestClassifier, RandomForestRegressor, GradientBoostingClassifier et GradientBoostingRegressor soutiennent tous cela. 

14
ClimbsRocks

Nous avons récemment publié une bibliothèque ( https://github.com/TeamHG-Memex/eli5 ) qui permet de le faire: elle gère divers classificateurs de scikit-learn, des cas binaires/multiclasses, permet de mettre en évidence du texte. selon les valeurs des fonctionnalités, s'intègre à IPython, etc.

9
Mikhail Korobov

En fait, je devais découvrir l’importance des fonctionnalités sur mon classificateur NaiveBayes et bien que j’utilise les fonctions ci-dessus, je n’étais pas en mesure d’obtenir l’importance des fonctionnalités en fonction des classes. J'ai parcouru la documentation de scikit learn et peaufiné un peu les fonctions ci-dessus pour la trouver adaptée à mon problème. J'espère que ça vous aide aussi!

def important_features(vectorizer,classifier,n=20):
class_labels = classifier.classes_
feature_names =vectorizer.get_feature_names()
topn_class1 = sorted(Zip(classifier.feature_count_[0], feature_names),reverse=True)[:n]
topn_class2 = sorted(Zip(classifier.feature_count_[1], feature_names),reverse=True)[:n]
print("Important words in negative reviews")
for coef, feat in topn_class1:
    print(class_labels[0], coef, feat)
print("-----------------------------------------")
print("Important words in positive reviews")
for coef, feat in topn_class2:
    print(class_labels[1], coef, feat) 

Notez que votre classificateur (dans mon cas, NaiveBayes) doit avoir l'attribut feature_count_ pour que cela fonctionne.

2
Sai Sandeep

Ce n'est pas exactement ce que vous recherchez, mais un moyen rapide d'obtenir les plus grands coefficients de magnitude (en supposant que les colonnes de la structure de données d'un pandas sont vos noms): 

Vous avez formé le modèle comme: 

lr = LinearRegression()
X_train, X_test, y_train, y_test = train_test_split(df, Y, test_size=0.25)
lr.fit(X_train, y_train)

Obtenez les 10 plus grandes valeurs de coefficient négatif (ou changez en reverse = True pour le plus grand positif) comme: 

sorted(list(Zip(feature_df.columns, lr.coef_)), key=lambda x: x[1], 
reverse=False)[:10]
0
slevin886

RandomForestClassifier n'a pas encore de coef_ attrubute, mais ce sera le cas dans la version 0.17, je pense. Cependant, voir la classe RandomForestClassifierWithCoef dans Élimination des fonctionnalités récursives sur une forêt aléatoire à l'aide de scikit-learn . Cela peut vous donner quelques idées pour contourner la limitation ci-dessus.

0
Daisuke Aramaki

Vous pouvez également faire quelque chose comme ceci pour créer un graphique des caractéristiques d'importance par ordre:

importances = clf.feature_importances_
std = np.std([tree.feature_importances_ for tree in clf.estimators_],
         axis=0)
indices = np.argsort(importances)[::-1]

# Print the feature ranking
#print("Feature ranking:")


# Plot the feature importances of the forest
plt.figure()
plt.title("Feature importances")
plt.bar(range(train[features].shape[1]), importances[indices],
   color="r", yerr=std[indices], align="center")
plt.xticks(range(train[features].shape[1]), indices)
plt.xlim([-1, train[features].shape[1]])
plt.show()
0
Oleole