UndefinedMetricWarning: F-score не визначений і встановлюється на 0,0 у мітках без прогнозованих зразків


78

Я отримую цю дивну помилку:

classification.py:1113: UndefinedMetricWarning: F-score is ill-defined and being set to 0.0 in labels with no predicted samples.
'precision', 'predicted', average, warn_for)`

але потім він також друкує f-рахунок при першому запуску:

metrics.f1_score(y_test, y_pred, average='weighted')

Другий раз, коли я біжу, він дає рахунок без помилок. Чому так?

>>> y_pred = test.predict(X_test)
>>> y_test
array([ 1, 10, 35,  9,  7, 29, 26,  3,  8, 23, 39, 11, 20,  2,  5, 23, 28,
       30, 32, 18,  5, 34,  4, 25, 12, 24, 13, 21, 38, 19, 33, 33, 16, 20,
       18, 27, 39, 20, 37, 17, 31, 29, 36,  7,  6, 24, 37, 22, 30,  0, 22,
       11, 35, 30, 31, 14, 32, 21, 34, 38,  5, 11, 10,  6,  1, 14, 12, 36,
       25,  8, 30,  3, 12,  7,  4, 10, 15, 12, 34, 25, 26, 29, 14, 37, 23,
       12, 19, 19,  3,  2, 31, 30, 11,  2, 24, 19, 27, 22, 13,  6, 18, 20,
        6, 34, 33,  2, 37, 17, 30, 24,  2, 36,  9, 36, 19, 33, 35,  0,  4,
        1])
>>> y_pred
array([ 1, 10, 35,  7,  7, 29, 26,  3,  8, 23, 39, 11, 20,  4,  5, 23, 28,
       30, 32, 18,  5, 39,  4, 25,  0, 24, 13, 21, 38, 19, 33, 33, 16, 20,
       18, 27, 39, 20, 37, 17, 31, 29, 36,  7,  6, 24, 37, 22, 30,  0, 22,
       11, 35, 30, 31, 14, 32, 21, 34, 38,  5, 11, 10,  6,  1, 14, 30, 36,
       25,  8, 30,  3, 12,  7,  4, 10, 15, 12,  4, 22, 26, 29, 14, 37, 23,
       12, 19, 19,  3, 25, 31, 30, 11, 25, 24, 19, 27, 22, 13,  6, 18, 20,
        6, 39, 33,  9, 37, 17, 30, 24,  9, 36, 39, 36, 19, 33, 35,  0,  4,
        1])
>>> metrics.f1_score(y_test, y_pred, average='weighted')
C:\Users\Michael\Miniconda3\envs\snowflakes\lib\site-packages\sklearn\metrics\classification.py:1113: UndefinedMetricWarning: F-score is ill-defined and being set to 0.0 in labels with no predicted samples.
  'precision', 'predicted', average, warn_for)
0.87282051282051276
>>> metrics.f1_score(y_test, y_pred, average='weighted')
0.87282051282051276
>>> metrics.f1_score(y_test, y_pred, average='weighted')
0.87282051282051276

Крім того, чому 'precision', 'predicted', average, warn_for)з’являється повідомлення про помилку? Відкритої дужки не існує, чому чому вона закінчується закриваючою дужкою? Я запускаю sklearn 0.18.1 за допомогою Python 3.6.0 у середовищі conda у Windows 10.

Я також подивився тут і не знаю, чи це та сама помилка. Ця публікація SO також не має рішення.


9
У y_true є кілька міток, які не відображаються в y_pred, а отже, це неправильно визначено
Vivek Kumar

3
@VivekKumar Я також отримую те саме попередження. У мене є збалансований набір даних (500 + 500), і це попередження, схоже, з’являється під час clf = GridSearchCV(SVC(C=2), tuned_parameters, cv=cv, scoring='f1') clf.fit(X_train, y_train)фази. Було б чудово подивитися, що спричиняє попередження або як його виправити.
сальву

Відповіді:


111

Як зазначалося в коментарях, деякі мітки в y_true не відображаються в y_pred. У цьому випадку мітка "2" ніколи не передбачається:

>>> set(y_test) - set(y_pred)
{2}

Це означає, що для цієї етикетки не існує F-оцінки, і, таким чином, F-оцінка для цього випадку вважається 0,0. Оскільки ви вимагали середнього балу, ви повинні врахувати, що в розрахунок було включено бал 0, і саме тому scikit-learn показує вам це попередження.

Це призводить до того, що ви не бачите помилки вдруге. Як я вже згадував, це попередження , яке трактується інакше, ніж помилка в python. Поведінка за замовчуванням у більшості середовищ - показувати конкретне попередження лише один раз. Цю поведінку можна змінити:

import warnings
warnings.filterwarnings('always')  # "error", "ignore", "always", "default", "module" or "once"

Якщо ви встановите це перед імпортом інших модулів, ви побачите попередження кожного разу, коли запускаєте код.

Неможливо уникнути побачення цього попередження вперше, окрім налаштування warnings.filterwarnings('ignore'). Що ви можете зробити, це вирішити , що ви не зацікавлені в балах етикеток , що не були передбачені, а потім явно вказати ярлики є зацікавлені в (які ярлики , які були передбачені принаймні один раз):

>>> metrics.f1_score(y_test, y_pred, average='weighted', labels=np.unique(y_pred))
0.91076923076923078

У цьому випадку попередження не відображається.


2
Це чудова відповідь, але я застерігаю від вибору для обчислення оцінки f1 з використанням, unique(y_pred)оскільки це може дати оманливі оцінки.
Роберт Сім

@RobertSim, будь ласка, трохи детальніше про це розкажіть? Дякую.
Akash Kandpal

4
@ harrypotter0, я думаю, що він мав на увазі те, що використання unique(y_pred)як стандартної практики, не розуміючи, що ти робиш, може мати несподівані наслідки. Тут відбувається те, що мітки, які взагалі не були передбачені, просто ігноруються. Поки ви активно вирішите , що саме це вас цікавить, це нормально. Використовуючи цей метод, я особисто завжди роздруковував непередбачувані мітки (використовуючи операції встановлення на початку відповіді), щоб переконатись, що я цього не прогадаю.
Шовальт,

Я маю на увазі це питання, оскільки маю подібну проблему. У моєму випадку, коли я перевіряю довжину, y_testа y_predті мають однакову довжину. То як це може бути неправильно визначеним, коли кожна справжня мітка має передбачений ярлик?
akalanka

3
@akalanka, спробуйте використати np.unique(y_pred)та np.unique(y_test). Вони, мабуть, мають різну довжину. Усі ваші ys мають передбачену мітку, але не всі мітки були передбачені хоча б раз.
Шовальт

4

Відповідно до відповіді @ Shovalt, але коротко:

Крім того, ви можете використовувати наступні рядки коду

    from sklearn.metrics import f1_score
    metrics.f1_score(y_test, y_pred, labels=np.unique(y_pred))

Це повинно видалити ваше попередження і дати вам результат, який ви хотіли, оскільки він більше не враховує різницю між наборами, використовуючи унікальний режим.


4
Це дублікат відповіді Шовальта.
норманій

3

Прийнята відповідь уже добре пояснює, чому виникає попередження. Якщо ви просто хочете контролювати попередження, можна скористатися ними precision_recall_fscore_support. Він пропонує (напівофіційний) аргумент, warn_forякий можна використовувати для приглушення попереджень.

(_, _, f1, _) = metrics.precision_recall_fscore_support(y_test, y_pred,
                                                        average='weighted', 
                                                        warn_for=tuple())

Як уже зазначалося в деяких коментарях, використовуйте це обережно.


1
Ні, шукаючи джерело sklearn, я знайшов цей варіант лише для precision_recall_fscore_support().
normanius

3

та сама проблема також трапилася зі мною, коли я навчав свою класифікаційну модель. причиною цієї проблеми є те, що в попереджувальному повідомленні сказано "в мітках без попередньо встановлених зразків", це призведе до ділення нуля при обчисленні f1-балу. Я знайшов інше рішення, коли прочитав документ sklearn.metrics.f1_score , є примітка наступне:

Коли істинно позитивне + хибнопозитивне == 0, точність не визначена; Коли істинно позитивне + хибнонегативне == 0, відкликання не визначено. У таких випадках за замовчуванням метрика буде встановлена ​​на 0, як і f-score, а UndefinedMetricWarning буде піднято. Цю поведінку можна змінити за допомогою zero_division

zero_divisionзначення за замовчуванням - "warn"ви можете встановити його на 0або, 1щоб уникати UndefinedMetricWarning. це працює для мене;) о, почекайте, є ще одна проблема, коли я використовую zero_division, мій sklearn повідомляє, що такого аргументу ключового слова за допомогою scikit-learn 0.21.3 немає. Просто оновіть свою sklearn до останньої версії, запустившиpip install scikit-learn -U


1

Як я помітив, ця помилка трапляється за двох обставин,

  1. Якщо ви використовували train_test_split () для розділення даних, вам слід переконатись, що ви скидаєте індекс даних (особливо, коли їх беруть за допомогою об'єкта серії pandas): y_train, y_test індекси повинні бути скинуті. Проблема полягає в тому, що ви намагаєтесь використовувати одну з оцінок від sklearn.metrics, наприклад; precision_score, це спробує відповідати перемішаним індексам y_test, які ви отримали від train_test_split ().

тому використовуйте або np.array (y_test) для y_true в балах, або y_test.reset_index (drop = True)

  1. Знову ж таки, у вас все ще може бути ця помилка, якщо передбачуваний вами «Справжній позитивний результат» дорівнює 0, що використовується для точності, відкликання та f1_scores. Ви можете візуалізувати це за допомогою confusion_matrix. Якщо класифікація багатозначна і ви встановите параметр: середнє = 'зважене' / мікро / макрос, ви отримаєте відповідь, якщо діагональна лінія в матриці не дорівнює 0

Сподіваюся, це допомагає.


-1

Як зазначається в повідомленні про помилку, метод, який використовується для отримання оцінки F, є частиною sklearn "Класифікація" - таким чином говорять про "мітки".

У вас є проблема регресії? Sklearn пропонує метод "оцінки F" для регресії в групі "Вибір ознак": http://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.f_regression.html

Якщо у вас є проблема з класифікацією, відповідь @ Shovalt мені здається правильною.


Ви правильно вказали на різницю між регресією та класифікацією, але я дійшов висновку, що це проблема класифікації з дискретного характеру y_testі y_predу питанні.
Шовальт 04.03.18
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.