web-dev-qa-db-fra.com

Comment écrire un estimateur personnalisé dans sklearn et utiliser la validation croisée dessus?

Je voudrais vérifier l'erreur de prédiction d'une nouvelle méthode à travers la validation croisée. Je voudrais savoir si je peux passer ma méthode à la fonction de validation croisée de sklearn et au cas où comment.

Je voudrais quelque chose comme sklearn.cross_validation(cv=10).mymethod.

J'ai aussi besoin de savoir comment définir mymethod si c'est une fonction et quel élément d'entrée et quelle sortie

Par exemple, nous pouvons considérer comme mymethod une implémentation de l'estimateur des moindres carrés (bien sûr pas ceux de sklearn).

J'ai trouvé ce tutoriel link mais ce n'est pas très clair pour moi.

Dans le documentation ils utilisent

>>> import numpy as np
>>> from sklearn import cross_validation
>>> from sklearn import datasets
>>> from sklearn import svm

>>> iris = datasets.load_iris()
>>> iris.data.shape, iris.target.shape
((150, 4), (150,))

 >>> clf = svm.SVC(kernel='linear', C=1) 
 >>> scores = cross_validation.cross_val_score(
 ...    clf, iris.data, iris.target, cv=5)
 ...
 >>> scores      

Mais le problème est qu'ils utilisent comme estimateur clf qui est obtenu par une fonction construite en sklearn. Comment dois-je définir mon propre estimateur pour pouvoir le passer au cross_validation.cross_val_score fonction?

Supposons par exemple un estimateur simple qui utilise un modèle linéaire $ y = x\beta $ où beta est estimé comme X [1,:] + alpha où alpha est un paramètre. Comment dois-je compléter le code?

class my_estimator():
      def fit(X,y):
          beta=X[1,:]+alpha #where can I pass alpha to the function?
          return beta
      def scorer(estimator, X, y) #what should the scorer function compute?
          return ?????

Avec le code suivant, j'ai reçu une erreur:

class my_estimator():
    def fit(X, y, **kwargs):
        #alpha = kwargs['alpha']
        beta=X[1,:]#+alpha 
        return beta

>>> cv=cross_validation.cross_val_score(my_estimator,x,y,scoring="mean_squared_error")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\site-packages\scikit_learn-0.14.1-py2.7-win32.Egg\sklearn\cross_validation.py", line 1152, in cross_val_score
    for train, test in cv)
  File "C:\Python27\lib\site-packages\scikit_learn-0.14.1-py2.7-win32.Egg\sklearn\externals\joblib\parallel.py", line 516, in __call__
    for function, args, kwargs in iterable:
  File "C:\Python27\lib\site-packages\scikit_learn-0.14.1-py2.7-win32.Egg\sklearn\cross_validation.py", line 1152, in <genexpr>
    for train, test in cv)
  File "C:\Python27\lib\site-packages\scikit_learn-0.14.1-py2.7-win32.Egg\sklearn\base.py", line 43, in clone
    % (repr(estimator), type(estimator)))
TypeError: Cannot clone object '<class __main__.my_estimator at 0x05ACACA8>' (type <type 'classobj'>): it does not seem to be a scikit-learn estimator a it does not implement a 'get_params' methods.
>>> 
27
Donbeo

La réponse réside également dans sklearn documentation .

Vous devez définir deux choses:

  • un estimateur qui implémente la fonction fit(X, y), X étant la matrice avec les entrées et y étant le vecteur des sorties

  • une fonction scorer, ou un objet appelable qui peut être utilisé avec: scorer(estimator, X, y) et renvoie le score du modèle donné

En vous référant à votre exemple: tout d'abord, scorer ne devrait pas être une méthode de l'estimateur, c'est une notion différente. Créez simplement un appelable:

def scorer(estimator, X, y)
    return ?????  # compute whatever you want, it's up to you to define
                  # what does it mean that the given estimator is "good" or "bad"

Ou encore une solution plus simple: vous pouvez passer une chaîne 'mean_squared_error' ou 'accuracy' (liste complète disponible dans cette partie de la documentation ) à cross_val_score fonction pour utiliser un marqueur prédéfini.

Une autre possibilité consiste à utiliser make_scorer fonction d'usine.

Quant à la deuxième chose, vous pouvez passer des paramètres à votre modèle via le fit_paramsdict paramètre du cross_val_score fonction (comme mentionné dans la documentation). Ces paramètres seront passés à la fonction fit.

class my_estimator():
    def fit(X, y, **kwargs):
        alpha = kwargs['alpha']
        beta=X[1,:]+alpha 
        return beta

Après avoir lu tous les messages d'erreur, qui donnent une idée assez claire de ce qui manque, voici un exemple simple:

import numpy as np
from sklearn.cross_validation import cross_val_score

class RegularizedRegressor:
    def __init__(self, l = 0.01):
        self.l = l

    def combine(self, inputs):
        return sum([i*w for (i,w) in Zip([1] + inputs, self.weights)])

    def predict(self, X):
        return [self.combine(x) for x in X]

    def classify(self, inputs):
        return sign(self.predict(inputs))

    def fit(self, X, y, **kwargs):
        self.l = kwargs['l']
        X = np.matrix(X)
        y = np.matrix(y)
        W = (X.transpose() * X).getI() * X.transpose() * y

        self.weights = [w[0] for w in W.tolist()]

    def get_params(self, deep = False):
        return {'l':self.l}

X = np.matrix([[0, 0], [1, 0], [0, 1], [1, 1]])
y = np.matrix([0, 1, 1, 0]).transpose()

print cross_val_score(RegularizedRegressor(),
                      X,
                      y, 
                      fit_params={'l':0.1},
                      scoring = 'mean_squared_error')
24
BartoszKP