Sklearn.metrics.mean_squared_error() возвращает отрицательное число

#python-3.x #machine-learning #scikit-learn

Вопрос:

Я хочу понять, почему sklearn.metrics.mean_squared_error() возвращают отрицательное число? Я знаю, что это невозможно, но это то, что происходит на моей машине, на самом деле 2 машины. Я использую Python 3.6 и sklearn(0.0).

Код:

 from sklearn.metrics import mean_squared_error
predictions = [96271]
test = [35241]
mse = mean_squared_error(test, predictions)
print('MSE: %.3f' % mse)

Ouput: MSE: -570306396.000
 

Вот скриншот отладчика, показывающий отрицательное значение:
введите описание изображения здесь

Комментарии:

1. Не удается воспроизвести; получение MSE: 3724660900.000 , как указано @StupidWolf в их ответе ниже. Голосование закрыть как невоспроизводимое.

Ответ №1:

С новым кодом проблема, похоже, заключается просто в переполнении int

 >>> from sklearn.metrics import mean_squared_error
>>> predictions = [96271]
>>> test = [35241]
>>> mean_squared_error(test, predictions)
-570306396.0
>>> np.float32(96271 - 35241)**2
3724660900
>>> np.int32(96271 - 35241)**2
-570306396
 

Естественный вопрос в том, когда он сломается, поскольку встроенный python int не будет переполняться

 >>> (96271 - 35241)**2
3724660900
 

Таким образом, проблема возникает, когда scikit learn обертывает ваши данные в массив numpy в

     y_type, y_true, y_pred, multioutput = _check_reg_targets(
        y_true, y_pred, multioutput)
 

который определяет ваш тип данных как int32 и выводит np.массив(…, dtype=np.int32), который затем переполняется.

Обратите внимание, что просто убедитесь, что все выглядит как поплавки, тоже будет работать

 >>> from sklearn.metrics import mean_squared_error
>>> predictions = [96271.] # Note the dot!
>>> test = [35241.]
>>> mean_squared_error(test, predictions)
3724660900
 

Комментарии:

1. Да, это сработало ! Спасибо. Будучи новичком в Python и ML, такое поведение удивительно, это где-то задокументировано или это просто то, как работает Python ?

2. Вот как работает арифметика с фиксированной точностью для целых чисел. Встроенное целое число Python имеет гибкий размер, поэтому не потерпит неудачу таким образом, но numpy-это, по сути, кусок кода c , который более … строг и его легко взломать. Вы можете прочитать больше о типах numpy и переполнениях здесь: numpy.org/doc/stable/user/…

Ответ №2:

Единственный способ, которым MSE может быть отрицательным, — это если вы указали sample_weights (или multioutput ), что это отрицательно. например

 mean_squared_error([0, 0], [1, 0], sample_weight=[-1, 1.2])
-5.000000000000001
 

поскольку то, что делает sklearn, — это сначала берет квадрат разностей, а затем взвешенное среднее с использованием

 avg = sum(a * weights) / sum(weights)
 

что может быть отрицательным, если некоторый вес отрицателен, но сумма положительна.

Из первоисточника:

     y_type, y_true, y_pred, multioutput = _check_reg_targets(
        y_true, y_pred, multioutput)
    check_consistent_length(y_true, y_pred, sample_weight)
    output_errors = np.average((y_true - y_pred) ** 2, axis=0,
                               weights=sample_weight)

    if not squared:
        output_errors = np.sqrt(output_errors)

    if isinstance(multioutput, str):
        if multioutput == 'raw_values':
            return output_errors
        elif multioutput == 'uniform_average':
            # pass None as weights to np.average: uniform mean
            multioutput = None

    return np.average(output_errors, weights=multioutput)
 

В частности, обратите внимание на

 output_errors = np.average((y_true - y_pred) ** 2, axis=0,
                               weights=sample_weight)
 

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

Есть тема, обсуждающая сомнительный выбор авторов numpy для принятия отрицательных весов при усреднении https://github.com/numpy/numpy/issues/9825, но сейчас, в 2021 году, средний показатель все еще принимает эти веса и действует таким образом, что это может удивить людей.

Комментарии:

1. Спасибо за разъяснение, но я не предоставил sample_weights (или multioutput), просто пару списков положительных чисел. Потратил некоторое время, пытаясь понять это, но не смог, в настоящее время используя mean_absolute_error.

2. пожалуйста, приведите воспроизводимый пример, поскольку это действительно кажется невозможным из кода. Команда Scikit learn также выиграла бы от сообщения об ошибке, если это действительно происходит.

Ответ №3:

Я не могу воспроизвести вашу ошибку, я на Python 3.8.5, sklearn 0.24.1, numpy 1.20.1 Я получаю:

 mse = mean_squared_error(test, predictions)
print('MSE: %.3f' % mse)
MSE: 3724660900.000
 

Глядя на цифры, я предполагаю, что при расчете они по умолчанию имеют значение np.int32, поэтому квадрат ваших значений превышает 2 147 483 647. Вы можете попробовать:

 mean_squared_error(np.float64(test),np.float64(predictions))
 

Возможно, было бы неплохо проверить вашу версию numpy / scikit-learn

Комментарии:

1. Не может воспроизвести ни то, ни другое; голосование за закрытие как таковое.