Пользователь не может получить доступ к среднему значению после подгонки - PullRequest
5 голосов
/ 19 февраля 2020

Я пытаюсь создать собственный оценщик на основе scikit learn. Я написал ниже фиктивный код, чтобы объяснить мою проблему. В методе оценки я пытаюсь получить доступ к mean_, рассчитанному в форме. Но я не в состоянии. Что я делаю не так? Я перепробовал много вещей и сделал это, ссылаясь на три четыре статьи. Но не нашел проблему.

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

Это фиктивная программа. Не go тем, что он пытается сделать.

import numpy as np
from sklearn.model_selection import cross_val_score


class FilterElems:
    def __init__(self, thres):
        self.thres = thres

    def fit(self, X, y=None, **kwargs):
        self.mean_ = np.mean(X)
        self.std_ = np.std(X)
        return self

    def predict(self, X):
        #         return sign(self.predict(inputs))
        X = (X - self.mean_) / self.std_
        return X[X > self.thres]

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

    def score(self, *x):
        print(self.mean_)  # errors out, mean_ and std_ are wiped out
        if len(x[1]) > 50:
            return 1.0
        else:
            return 0.5


model = FilterElems(thres=0.5)
print(cross_val_score(model,
                      np.random.randint(1, 1000, (100, 100)),
                      None,
                      scoring=model.score,
                      cv=5))

Ошибка:

AttributeError: у объекта 'FilterElems' нет атрибута 'mean _'

Ответы [ 2 ]

3 голосов
/ 28 февраля 2020

Вы почти на месте.

Подпись для бомбардира scorer(estimator, X, y). cross_val_score вызывает метод scorer, передавая объект estimator в качестве первого параметра. Поскольку ваша подпись scorer является функцией переменного аргумента, первый элемент будет содержать estimator

, чтобы изменить ваш счет на

def score(self, *x):
    print(x[0].mean_)
    if len(x[1]) > 50:
        return 1.0
    else:
        return 0.5

Рабочий код

import numpy as np
from sklearn.model_selection import cross_val_score

class FilterElems:
    def __init__(self, thres):
        self.thres = thres

    def fit(self, X, y=None, **kwargs):
        self.mean_ = np.mean(X)
        self.std_ = np.std(X)
        return self

    def predict(self, X):
        X = (X - self.mean_) / self.std_
        return X[X > self.thres]

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

    def score(self, estimator, *x):
        print(estimator.mean_, estimator.std_) 
        if len(x[0]) > 50:
            return 1.0
        else:
            return 0.5

model = FilterElems(thres=0.5)
print(cross_val_score(model,
                      np.random.randint(1, 1000, (100, 100)),
                      None,
                      scoring=model.score,
                      cv=5))

Outout

504.750125 288.84916035447355
501.7295 289.47825925231416
503.743375 288.8964170227962
503.0325 287.8292687406025
500.041 289.3488678377712
[0.5 0.5 0.5 0.5 0.5]
2 голосов
/ 23 февраля 2020

Для ввода scoring параметра в cross_val_score необходимо str или callable с подписью scoring(estimator, X, y). В вашем случае вам, кажется, не нужно y, поэтому вы можете оставить это в своем вызове. Кроме того, вы должны убедиться, что результат оценки будет иметь одно значение.

Решение будет выглядеть примерно так для вашей проблемы.

import numpy as np
from sklearn.model_selection import cross_val_score
from sklearn.base import TransformerMixin

class FilterElems(TransformerMixin):
    def __init__(self, thres):
        self.thres = thres

    def fit(self, X, y=None, **kwargs):
        self.mean_ = np.mean(X)
        self.std_ = np.std(X)
        return self

    def predict(self, X):
        #         return sign(self.predict(inputs))
        X = (X - self.mean_) / self.std_
        return X[X > self.thres]

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


def scorer(tranformer, X):
    print(tranformer.mean_)  # Now it prints out, mean_ and std_ 
    result=[]
    for x in X:
        # do the stuff you want here
        if x[1] > 50:
            result.append(1)
        else:
            result.append(0.5)
    # but return a single value
    return np.mean(result)

np.random.seed(1)
model = FilterElems(thres=0.5)
print(cross_val_score(model,
                      np.random.randint(1, 1000, (100, 100)),
                      None,
                      scoring=scorer,
                      cv=5))

# [0.95  1.    1.    0.975 0.975]

...