Scikit-learn: MSE отрицательно, когда возвращается cross_val_score

Созданный на 12 сент. 2013  ·  58Комментарии  ·  Источник: scikit-learn/scikit-learn

Среднеквадратичная ошибка, возвращаемая sklearn.cross_validation.cross_val_score, всегда отрицательна. Хотя это продуманное решение, позволяющее использовать выходные данные этой функции для максимизации с учетом некоторых гиперпараметров, при непосредственном использовании cross_val_score это крайне сбивает с толку. По крайней мере, я спросил себя, как среднее значение квадрата может быть отрицательным, и подумал, что cross_val_score работает неправильно или не использует предоставленную метрику. Только покопавшись в исходном коде sklearn, я понял, что знак перевернулся.

Это поведение упоминается в make_scorer в scorer.py, однако оно не упоминается в cross_val_score, и я думаю, что должно быть, потому что в противном случае люди думают, что cross_val_score работает неправильно.

API Bug Documentation

Самый полезный комментарий

может негмс решит проблему

Все 58 Комментарий

Вы имеете в виду

greater_is_better : boolean, default=True

Whether score_func is a score function (default), meaning high is good, 
or a loss function, meaning low is good. In the latter case, the scorer 
object will sign-flip the outcome of the score_func.

в http://scikit-learn.org/stable/modules/generated/sklearn.metrics.make_scorer.html
? (просто для справки)

Я согласен, что это может быть более понятно в документации cross_val_score

Спасибо за сообщение

Действительно, мы упустили эту проблему из виду при рефакторинге Scorer. Следующее очень противоречит интуиции:

>>> import numpy as np
>>> from sklearn.datasets import load_boston
>>> from sklearn.linear_model import RidgeCV
>>> from sklearn.cross_validation import cross_val_score

>>> boston = load_boston()
>>> np.mean(cross_val_score(RidgeCV(), boston.data, boston.target, scoring='mean_squared_error'))
-154.53681864311497

/ cc @larsmans

Кстати, я не согласен, что это проблема с документацией. Это cross_val_score Должно вернуть значение со знаком, соответствующим имени оценки. В идеале GridSearchCV(*params).fit(X, y).best_score_ тоже должны быть последовательными. В противном случае API очень сбивает с толку.

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

Объект счетчика может просто хранить флаг greater_is_better и всякий раз, когда используется счетчик, знак может быть перевернут в случае необходимости, например, в GridSearchCV .

Я согласен с тем, что у нас есть проблема с удобством использования, но я не полностью согласен с решением @ogrisel о том, что мы должны

вернуть значение со знаком, который соответствует названию подсчета очков

потому что это ненадежный взлом в долгосрочной перспективе. Что, если кто-то определит индивидуального бомбардира с таким именем, как mse ? Что, если они действительно следуют шаблону именования, но заключат исполнителя в декоратор, который меняет имя?

Объект счетчика может просто хранить флаг great_is_better, и всякий раз, когда он используется, знак может быть перевернут в случае необходимости, например, в GridSearchCV.

Это то, что изначально делали скорекеры, во время разработки между выпусками 0.13 и 0.14, и это значительно усложнило их определение. Это также затрудняло отслеживание кода, потому что атрибут greater_is_better казалось, исчез в коде счетчика, только чтобы снова появиться в середине кода поиска сетки. Для того, чтобы делать что-то, что в идеале подойдет простая функция, нужен был специальный класс Scorer .

Я считаю, что если мы хотим оптимизировать оценки, то они должны быть максимизированы. Для удобства пользователя, я думаю, мы могли бы ввести параметр score_is_loss["auto", True, False] который изменяет только _display_ оценок и может использовать эвристику на основе встроенных имен.

Это был поспешный ответ, потому что мне пришлось выйти из поезда. То, что я имел в виду под «отображением», на самом деле является возвращаемым значением из cross_val_score . Я считаю, что счетчики должны быть простыми и единообразными, а алгоритмы всегда должны быть максимально точными.

Это приводит к асимметрии между встроенными и настраиваемыми счетчиками.

Пинг @GaelVaroquaux.

Мне нравится решение score_is_loss или что-то в этом роде ... изменение знака для соответствия имени подсчета очков, кажется, трудно поддерживать, может вызвать проблемы, как упоминал @larsmans

какой вывод, какое решение мы должны искать? :)

@tdomhan @jaquesgrobler @larsmans Вы знаете, применимо ли это и к r2 ? Я заметил, что оценки r2 возвращаемые GridSearchCV , также в основном отрицательны для ElasticNet , Lasso и Ridge .

R² может быть как положительным, так и отрицательным, а отрицательное просто означает, что ваша модель работает очень плохо.

IIRC, @GaelVaroquaux был сторонником возврата отрицательного числа, когда greater_is_better=False .

r2 - это функция оценки (больше - лучше), поэтому она должна быть положительной, если ваша модель хоть сколько-нибудь хороша, но это одна из немногих метрик производительности, которая на самом деле может быть отрицательной, то есть хуже 0.

Каков консенсус по этому вопросу? На мой взгляд, cross_val_score - это инструмент оценки, а не выбор модели. Таким образом, он должен вернуть исходные значения.

Я могу исправить это в моем PR # 2759, так как внесенные мной изменения очень легко исправить. Уловка состоит в том, чтобы не переворачивать знак вперед, а вместо этого получить доступ к атрибуту greater_is_better на счетчике при выполнении поиска по сетке.

Каков консенсус по этому вопросу? На мой взгляд, cross_val_score - это
инструмент оценки, а не инструмент выбора модели. Таким образом, он должен вернуться
исходные значения.

Особый случай - различное поведение, являющееся источником проблем в программном обеспечении.

Я просто думаю, что нам следует переименовать "mse" в "negated_mse" в списке.
приемлемых оценочных строк.

Что, если кто-то определит индивидуального бомбардира с таким именем, как mse? Что, если они действительно следуют шаблону именования, но заключат исполнителя в декоратор, который меняет имя?

Я не думаю, что @ogrisel предлагал использовать сопоставление имен только для того, чтобы соответствовать исходной метрике. Поправьте меня, если я ошибаюсь @ogrisel.

Я просто думаю, что мы должны переименовать «mse» в «negated_mse» в списке приемлемых строк оценки.

Это совершенно не интуитивно, если вы не знакомы с внутренним устройством scikit-learn. Если вам придется так согнуть систему, я думаю, это признак того, что есть проблема с дизайном.

Это совершенно не интуитивно, если вы не знакомы с внутренним устройством scikit-learn.
Если вам придется вот так гнуть систему, я думаю, это знак того, что есть
проблема дизайна.

Я не согласен. Люди понимают вещи с большим количеством предварительных знаний и
контекст. Все они носят систематический характер. Пытаюсь встроить это в программное обеспечение
дает список покупок как набор особых случаев. Мало того, что это делает
программное обеспечение сложно поддерживать, но это также означает, что люди, у которых нет
в виду эти исключения сталкиваются с неожиданным поведением и пишут ошибочные
код с использованием библиотеки.

Какой особый случай вы имеете в виду?

Для ясности, я думаю, что оценки перекрестной проверки, хранящиеся в объекте GridSearchCV должны _также_ быть исходными значениями (не с перевернутым знаком).

AFAIK, переворачивание знака было введено, чтобы сделать реализацию поиска по сетке немного проще, но не должно было влиять на удобство использования.

Какой особый случай вы имеете в виду?

Что ж, тот факт, что для одних показателей лучше, а для других
это наоборот.

AFAIK, было введено переворачивание знака, чтобы поиск по сетке
реализация немного проще, но не должна была влиять на
удобство использования.

Речь идет не о поиске по сетке, а о разделении задач: оценки
должны быть пригодными для использования, ничего не зная о них, иначе код для
их специфика распространится на всю кодовую базу. Есть
уже много скорингового кода.

Но это несколько откладывает проблему на пользовательский код. Никто не хочет строить «отрицательную MSE», чтобы пользователям приходилось возвращать знаки в свой код. Это неудобно, особенно для отчетов о перекрестной проверке с несколькими показателями (PR # 2759), поскольку вам необходимо обрабатывать каждую метрику отдельно. Интересно, можем ли мы получить лучшее из обоих миров: общий код и интуитивно понятные результаты.

Но это несколько откладывает проблему на пользовательский код. Никто не хочет
для построения "отрицательной MSE", чтобы пользователям пришлось переворачивать знаки в своих
код.

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

Это неудобно, особенно для многомерной перекрестной проверки.
отчеты (PR # 2759), так как вам нужно обрабатывать каждую метрику отдельно.

Почему. Если вы просто согласитесь с тем, что чем больше, тем лучше, это сделает
все проще, включая интерпретацию результатов.

Интересно, можем ли мы получить лучшее из обоих миров: общий код и
интуитивно понятные результаты.

Риск состоит в том, что у нас есть очень сложный код, который замедляет обслуживание
и развитие. Scikit-learn набирает вес.

Если вы просто согласитесь, что всегда больше, тем лучше

Это то, что она сказала :)

Если серьезно, я думаю, что одна из причин, по которой это сбивает людей с толку, заключается в том, что результат cross_val_score не согласуется с показателями. Если мы будем следовать вашей логике, все метрики в sklearn.metrics должны иметь вид «больше - лучше».

Это то, что она сказала :)

Хороший!

Если серьезно, я думаю, что одна из причин, по которой это сбивает людей с толку, заключается в том, что
вывод cross_val_score не соответствует метрикам. Если мы
следуйте своей логике, все метрики в sklearn.metrics должны следовать "больше
лучше".

Согласовано. Вот почему мне нравится идея изменить название: оно всплывает
в глаза людям.

Если серьезно, я думаю, что одна из причин, по которой это сбивает людей с толку, заключается в том, что вывод cross_val_score не соответствует метрикам.

А это, в свою очередь, делает scoring более загадочным, чем оно есть на самом деле.

Укусил это сегодня в версии 0.16.1 при попытке выполнить линейную регрессию. Хотя знак оценки, по-видимому, больше не меняется для классификаторов, он все еще меняется для линейной регрессии. Чтобы усугубить путаницу, LinearRegression.score () возвращает неперевернутую версию счета.

Я бы посоветовал сделать все согласованным и вернуть оценку без переворота для линейных моделей.

Пример:

from sklearn import linear_model
from sklearn.naive_bayes import GaussianNB
from sklearn import cross_validation
from sklearn import datasets
iris = datasets.load_iris()
nb = GaussianNB()
scores = cross_validation.cross_val_score(nb, iris.data, iris.target)
print("NB score:\t  %0.3f" % scores.mean() )

iris_reg_data = iris.data[:,:3]
iris_reg_target = iris.data[:,3]
lr = linear_model.LinearRegression()
scores = cross_validation.cross_val_score(lr, iris_reg_data, iris_reg_target)
print("LR score:\t %0.3f" % scores.mean() )

lrf = lr.fit(iris_reg_data, iris_reg_target)
score = lrf.score(iris_reg_data, iris_reg_target)
print("LR.score():\t  %0.3f" % score )

Это дает:

NB score:     0.934    # sign is not flipped
LR score:    -0.755    # sign is flipped
LR.score():   0.938    # sign is not flipped

Перекрестная проверка переворачивает все признаки моделей: чем больше, тем лучше. Я все еще не согласен с этим решением. Я думаю, что основными сторонниками этого были @GaelVaroquaux и, возможно, @mblondel [я вспомнил, как вы реорганизовали код

Да ладно, все обсуждение выше.
Мне кажется, что в mse по умолчанию знак переворачивается, а r2 еще менее интуитивно понятен: - /

@Huitzilo GaussianNB - это классификатор, который по умолчанию использует точность. LinearRegression - это регрессор, который использует оценку r2 в качестве счетчика по умолчанию. Вторая оценка отрицательная, но помните, что оценка r2 _ может быть отрицательной. Кроме того, радужная оболочка - это мультиклассовый набор данных. Следовательно, цели категоричны. Вы не можете использовать регрессор.

правильно, я немного запутался, что происходит, r2 не переворачивается ... только mse будет.

Может быть, решение всей проблемы - переименовать вещь в negmse ?

@mblondel конечно ты прав, извини. Я просто быстро придумал пример регрессии и, будучи самоуверенным в данных по радужной оболочке глаза, подумал, что предсказание признака №4 от других сработает (с положительным R2). Но этого не произошло, следовательно, отрицательный R2. Никаких указателей здесь нет. ХОРОШО. Виноват.

Тем не менее, в MSE, которую я получаю от cross_val_score , знак перевернут.

Может быть, это только я, но меня это несоответствие сильно сбивает с толку (именно поэтому я столкнулся с этой проблемой). Почему следует менять знак MSE, а не R2?

Может быть, это только я, но меня это несоответствие сильно сбивает с толку (именно поэтому я столкнулся с этой проблемой). Почему следует менять знак MSE, а не R2?

Чем выше семантика оценки, тем лучше. Высокая MSE - это плохо.

может негмс решит проблему

@amueller Я согласен, явное

Возможно, документация на [1] также могла бы быть еще более ясной о том, как меняются знаки для некоторых оценок. В моем случае мне нужна была информация быстро, и я смотрел только таблицу в разделе 3.1.1.1, но не читал текст (который объясняет принцип «больше - лучше»). IMHO, добавление комментария для mse, median и средней абсолютной ошибки в таблице под 3.1.1.1, указывающее на их отрицание, уже очень поможет, без каких-либо изменений в фактическом коде.

[1] http://scikit-learn.org/stable/modules/model_evaluation.html#scoring -parameter

Я наткнулся на очень интересный случай:

from sklearn.cross_validation import cross_val_score
model = LinearRegression()
scores = cross_val_score(model, X, target, cv=2, scoring='r2')
scores

Результаты в

array([-0.17026282, -2.21315179])

Для того же набора данных следующий код

model = LinearRegression()
model.fit(X, target)
prediction = model.predict(X)
print r2_score(target, prediction)

приводит к разумной стоимости

0.353035789318

AFAIK для модели линейной регрессии (с перехватом) нельзя получить R ^ 2> 1 или R ^ 2 <0

Таким образом, результат cv не выглядит как R ^ 2 с перевернутым знаком. Я ошибаюсь в какой-то момент?

r2 может быть отрицательным (для плохих моделей). Он не может быть больше 1.

Вы, вероятно, переобучаете. пытаться:

from sklearn.cross_validation import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, target, test_size=0.2, random_state=0)
model = LinearRegression()
model.fit(X_train, y_train)
pred_train = model.predict(X_train)
print("train r2: %f" % r2_score(y_train, pred_train))

pred_test = model.predict(X_test)
print("test r2: %f" % r2_score(y_test, pred_test))

Попробуйте использовать другие значения для начального числа random_state integer, которое управляет случайным разбиением.

может негмс решит проблему

+1 для 'neg_mse' (я думаю, что подчеркивание делает вещи более читаемыми).

Это решит все проблемы? Были ли другие оценки больше не лучше?

Есть:

  • log_loss
  • mean_absolute_error
  • median_absolute_error

Согласно doc/modules/model_evaluation.rst , это должны быть все они.

И hinge_loss наверное?

Добавление префикса neg_ ко всем этим потерям кажется неудобным.

Идея состояла бы в том, чтобы вернуть исходные оценки (без переворота знака), но вместо возврата ndarray мы возвращаем класс, который расширяет ndarray такими методами, как best() , arg_best() , best_sorted() . Таким образом, результаты неудивительны, и у нас есть удобные методы для получения наилучших результатов.

Нет счетчика потери шарнира (и я никогда не видел, чтобы его использовали для оценки).

Счетчик не возвращает массив numpy, он возвращает число с плавающей запятой, верно?
мы могли бы вернуть объект оценки, который имеет особый символ ">", но выглядит как плавающее.
Мне это кажется более надуманным, чем предыдущее решение, которое помечало счетчика логическим значением «lower_is_better», которое затем использовалось в GridSearchCV.

cross_val_score возвращает массив.

На самом деле оценки, возвращаемые cross_val_score обычно не нужно сортировать, их нужно просто усреднить.

Другая идея - добавить метод sorted к _BaseScorer .

my_scorer = make_scorer(my_metric, greater_is_better=False)
scores = my_scorer.sorted(scores)  # takes into account my_scorer._sign
best = scores[0]

cross_val_score возвращает массив, но счетчики возвращают число с плавающей точкой. Я считаю, что было бы странно иметь конкретную логику в cross_val_score потому что вы хотели бы иметь такое же поведение в GridSearchCV и во всех других объектах CV.

Вам также понадобится метод argsort, потому что в GridSearchCV вам нужен лучший результат и лучший индекс.

Как реализовать «оценивать средние и отклонения ошибок рабочих от контрольных вопросов, а затем вычислять средневзвешенное значение после удаления предполагаемого смещения для прогнозов» с помощью scikit-learn?

IIRC мы обсуждали это во время спринта (прошлым летом ?!) и решили пойти с neg_mse (или это было neg-mse ) и исключить все показатели / строки, в которых сейчас стоит отрицательный знак.
Это все еще консенсус? Тогда мы должны сделать это до 0.18.
Пинг @GaelVaroquaux @agramfort @jnothman @ogrisel @raghavrv

да договорились на neg_mse AFAIK

Это было neg_mse

Также нам понадобятся:

  • neg_log_loss
  • neg_mean_absolute_error
  • neg_median_absolute_error

model = Последовательный ()
keras.layers.Flatten ()
model.add (Dense (11, input_dim = 3, kernel_initializer = keras.initializers.he_normal (seed = 2),
kernel_regularizer = регуляризаторы.l2 (2)))
keras.layers.LeakyReLU (альфа = 0,1)
model.add (Dense (8, kernel_initializer = keras.initializers.he_normal (seed = 2)))
keras.layers.LeakyReLU (альфа = 0,1)
model.add (Dense (4, kernel_initializer = keras.initializers.he_normal (seed = 2)))
keras.layers.LeakyReLU (альфа = 0,1)
model.add (Dense (1, kernel_initializer = keras.initializers.he_normal (seed = 2)))
keras.layers.LeakyReLU (альфа = 0,2)
adag = RMSprop (lr = 0,0002)
model.compile (loss = loss.mean_squared_error,
optimizer = adag
)
history = model.fit (X_train, Y_train, epochs = 2000,
batch_size = 20, shuffle = True)

Как перекрестно проверить приведенный выше код? Я хочу, чтобы здесь не использовался один метод перекрестной проверки.

@shreyassks, это неправильное место для вашего вопроса, но я бы проверил это: https://keras.io/scikit-learn-api . Оберните свою сеть в оценщик scikit-learn затем используйте w / model_selection.cross_val_score

Да. Я абсолютно согласен! То же самое произошло с Brier_score_loss, он отлично работает с Brier_score_loss, но сбивает с толку, когда он исходит от GridSearchCV, возвращается отрицательный Brier_score_loss. По крайней мере, было бы лучше вывести что-то вроде, потому что Brier_score_loss - это потеря (чем ниже, тем лучше), функция подсчета здесь меняет знак, чтобы сделать его отрицательным.

Идея в том, что cross_val_score должен полностью сосредоточиться на абсолютном значении результата. Насколько мне известно, важность отрицательного знака (-), полученного для MSE (среднеквадратичная ошибка) в cross_val_score, не предопределена. Подождем выхода обновленной версии sklearn, в которой решена эта проблема.

Для варианта использования регрессии:
model_score = cross_val_score (модель, df_input, df_target, scoring = 'neg_mean_squared_error', cv = 3)
Я получаю следующие значения:

СВР:
[-6.20938025 -1.397376 -1.94519]
-3,183982080147279

Линейная регрессия:
[-5.94898085 -9.30931808 -1.15760676]
-5,4719685646934275

Лассо:
[-7.22363814 -10.47734135 -2.20807684]
-6,6363521107522345

Ридж:
[-5.95990385 -4.17946756 -1.36885809]
-3,8360764993832004

Так какой из них лучше?
СВР?

Для варианта использования регрессии:
Я получаю разные результаты, когда использую
(1) "cross_val_score" с оценкой = 'neg_mean_squared_error'
и
(2) Для тех же входных данных, когда я использую "GridSearchCV" и проверяю 'best_score_'

Для регрессионных моделей какая лучше?

  • "cross_val_score" с оценкой = 'neg_mean_squared_error'
    (ИЛИ ЖЕ)
  • используйте "GridSearchCV" и проверьте "best_score_"

@pritishban
Вы задаете вопрос об использовании. Средство отслеживания проблем в основном предназначено для обнаружения ошибок и новых функций. По вопросам использования рекомендуется попробовать Stack Overflow или Список рассылки .

Была ли эта страница полезной?
0 / 5 - 0 рейтинги