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

109

Я работаю над проблемой анализа настроений, данные выглядят так:

label instances
    5    1190
    4     838
    3     239
    1     204
    2     127

Таким образом, мои данные несбалансированы, поскольку 1190 instancesпомечены значком 5. Для классификации я использую SVC scikit . Проблема в том, что я не знаю, как правильно сбалансировать мои данные, чтобы точно вычислить точность, отзыв, точность и показатель f1 для случая мультикласса. Поэтому я попробовал следующие подходы:

Первый:

    wclf = SVC(kernel='linear', C= 1, class_weight={1: 10})
    wclf.fit(X, y)
    weighted_prediction = wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, weighted_prediction)
print 'F1 score:', f1_score(y_test, weighted_prediction,average='weighted')
print 'Recall:', recall_score(y_test, weighted_prediction,
                              average='weighted')
print 'Precision:', precision_score(y_test, weighted_prediction,
                                    average='weighted')
print '\n clasification report:\n', classification_report(y_test, weighted_prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, weighted_prediction)

Второй:

auto_wclf = SVC(kernel='linear', C= 1, class_weight='auto')
auto_wclf.fit(X, y)
auto_weighted_prediction = auto_wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, auto_weighted_prediction)

print 'F1 score:', f1_score(y_test, auto_weighted_prediction,
                            average='weighted')

print 'Recall:', recall_score(y_test, auto_weighted_prediction,
                              average='weighted')

print 'Precision:', precision_score(y_test, auto_weighted_prediction,
                                    average='weighted')

print '\n clasification report:\n', classification_report(y_test,auto_weighted_prediction)

print '\n confussion matrix:\n',confusion_matrix(y_test, auto_weighted_prediction)

Третий:

clf = SVC(kernel='linear', C= 1)
clf.fit(X, y)
prediction = clf.predict(X_test)


from sklearn.metrics import precision_score, \
    recall_score, confusion_matrix, classification_report, \
    accuracy_score, f1_score

print 'Accuracy:', accuracy_score(y_test, prediction)
print 'F1 score:', f1_score(y_test, prediction)
print 'Recall:', recall_score(y_test, prediction)
print 'Precision:', precision_score(y_test, prediction)
print '\n clasification report:\n', classification_report(y_test,prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, prediction)


F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1082: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
 0.930416613529

Однако я получаю такие предупреждения:

/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172:
DeprecationWarning: The default `weighted` averaging is deprecated,
and from version 0.18, use of precision, recall or F-score with 
multiclass or multilabel data or pos_label=None will result in an 
exception. Please set an explicit value for `average`, one of (None, 
'micro', 'macro', 'weighted', 'samples'). In cross validation use, for 
instance, scoring="f1_weighted" instead of scoring="f1"

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

new_with_python
источник
Так почему бы не добавить averageпараметр в третьем случае?
yangjie
1
@yangjie Я не знаю. Я просто проверяю документацию, но не понимаю, как правильно использовать метрики для несбалансированных данных. Не могли бы вы дать более широкое объяснение и пример? Спасибо!
new_with_python

Ответы:

164

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

Вес класса

Веса из class_weightпараметра используются для обучения классификатора . Они не используются при вычислении каких-либо показателей, которые вы используете : с разными весами классов числа будут разными просто потому, что классификатор другой.

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

Метрики

Если у вас есть классификатор, вы хотите знать, насколько хорошо он работает. Здесь вы можете использовать метрики вы упомянули: accuracy, recall_score, f1_score...

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

Я не буду подробно описывать все эти показатели, но отмечу, что, за исключением accuracy, они естественно применяются на уровне класса: как вы можете видеть в этом printотчете о классификации, они определены для каждого класса. Они полагаются на такие концепции, как true positivesили false negativeкоторые требуют определения того, какой класс является положительным .

             precision    recall  f1-score   support

          0       0.65      1.00      0.79        17
          1       0.57      0.75      0.65        16
          2       0.33      0.06      0.10        17
avg / total       0.52      0.60      0.51        50

Предупреждение

F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The 
default `weighted` averaging is deprecated, and from version 0.18, 
use of precision, recall or F-score with multiclass or multilabel data  
or pos_label=None will result in an exception. Please set an explicit 
value for `average`, one of (None, 'micro', 'macro', 'weighted', 
'samples'). In cross validation use, for instance, 
scoring="f1_weighted" instead of scoring="f1".

Вы получаете это предупреждение, потому что используете f1-score, отзыв и точность, не определяя, как они должны быть вычислены! Вопрос можно перефразировать: как вывести одно глобальное число для оценки f1 из приведенного выше отчета о классификации ? Ты мог:

  1. Возьмите средний балл f1 для каждого класса: это avg / totalрезультат выше. Это также называется макро- усреднением.
  2. Вычислите показатель f1, используя общее количество истинных положительных / ложных отрицательных результатов и т. Д. (Вы суммируете количество истинных положительных / ложных отрицательных результатов для каждого класса). Он же микро усреднение.
  3. Вычислите средневзвешенное значение f1-score. Использование 'weighted'в scikit-learn будет взвешивать оценку f1 с помощью поддержки класса: чем больше элементов имеет класс, тем важнее оценка f1 для этого класса в вычислениях.

Это 3 варианта в scikit-learn, предупреждение говорит о том, что вам нужно выбрать один . Таким образом, вы должны указать averageаргумент для метода оценки.

Какой из них вы выберете, зависит от того, как вы хотите измерить производительность классификатора: например, при макро-усреднении не учитывается дисбаланс классов, и оценка f1 класса 1 будет так же важна, как и оценка класса f1 5. Однако, если вы используете взвешенное усреднение, вы получите большее значение для класса 5.

Вся спецификация аргументов в этих метриках не очень ясна в scikit-learn прямо сейчас, она улучшится в версии 0.18, согласно документации. Они удаляют некоторые неочевидные стандартные действия и выдают предупреждения, чтобы разработчики это заметили.

Вычисление оценок

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

Вот способ сделать это, используя StratifiedShuffleSplit, который дает вам случайные части ваших данных (после перетасовки), которые сохраняют распределение меток.

from sklearn.datasets import make_classification
from sklearn.cross_validation import StratifiedShuffleSplit
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score, classification_report, confusion_matrix

# We use a utility to generate artificial classification data.
X, y = make_classification(n_samples=100, n_informative=10, n_classes=3)
sss = StratifiedShuffleSplit(y, n_iter=1, test_size=0.5, random_state=0)
for train_idx, test_idx in sss:
    X_train, X_test, y_train, y_test = X[train_idx], X[test_idx], y[train_idx], y[test_idx]
    svc.fit(X_train, y_train)
    y_pred = svc.predict(X_test)
    print(f1_score(y_test, y_pred, average="macro"))
    print(precision_score(y_test, y_pred, average="macro"))
    print(recall_score(y_test, y_pred, average="macro"))    

Надеюсь это поможет.

ldirer
источник
Как указать вес класса для мультикласса? Например, что class_weight={1:10}означает данные, имеющие 3 класса?
Азиз Джавед
Есть ли способ получить оценку точности по меткам?
Анкур Синха
Вы можете более четко объяснить, как работает микро. Также вы ничего не упоминаете о двоичных
файлах
Для меня расслоенное перемешивание создавало проблемы, поэтому я снова переключился на разделение на тренировку, как это было показано ValueError: The least populated class in y has only 1 member, which is too few. The minimum number of labels for any class cannot be less than 2.. Он отлично работает с разделением поезд-тест, но может ли кто-нибудь мне помочь, почему я получаю эту ошибку с SSS? Спасибо.
Акаш Кандпал
Привет, я протестировал ваш код, но у меня есть это сообщение об ошибке C: \ Users \\ Anaconda3 \ lib \ site-packages \ sklearn \ metrics \ classification.py: 976: DeprecationWarning: с версии 0.18 двоичный ввод не будет обрабатываться специально при использовании усредненная точность / отзывчивость / оценка F. Используйте average = 'binary', чтобы сообщать только о положительных результатах класса. 'положительная производительность класса.', DeprecationWarning)
Чеди Бечих
73

Здесь много очень подробных ответов, но я не думаю, что вы отвечаете на правильные вопросы. Насколько я понимаю вопрос, есть две проблемы:

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

1.

Вы можете использовать большинство функций оценки в scikit-learn как с проблемой мультикласса, так и с задачами одного класса. Например:

from sklearn.metrics import precision_recall_fscore_support as score

predicted = [1,2,3,4,5,1,2,1,1,4,5] 
y_test = [1,2,3,4,5,1,2,1,1,4,1]

precision, recall, fscore, support = score(y_test, predicted)

print('precision: {}'.format(precision))
print('recall: {}'.format(recall))
print('fscore: {}'.format(fscore))
print('support: {}'.format(support))

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

| Label | Precision | Recall | FScore | Support |
|-------|-----------|--------|--------|---------|
| 1     | 94%       | 83%    | 0.88   | 204     |
| 2     | 71%       | 50%    | 0.54   | 127     |
| ...   | ...       | ...    | ...    | ...     |
| 4     | 80%       | 98%    | 0.89   | 838     |
| 5     | 93%       | 81%    | 0.91   | 1190    |

Затем...

2.

... вы можете сказать, являются ли несбалансированные данные проблемой. Если оценка для менее представленных классов (класс 1 и 2) ниже, чем для классов с большим количеством обучающих выборок (класс 4 и 5), то вы знаете, что несбалансированные данные на самом деле являются проблемой, и вы можете действовать соответственно, как описано в некоторых других ответах в этой теме. Однако, если в данных, которые вы хотите прогнозировать, присутствует то же распределение классов, ваши несбалансированные данные обучения являются хорошим представителем данных, и, следовательно, дисбаланс - это хорошо.

wonderkid2
источник
1
Отличный пост и хорошо сказано. Спасибо
Алвис
1
Привет, еще один вопрос: как вы печатали этикетки с помощью precision_recall_fscore_support? Этикетки напечатаны по заказу?
BigD
@BigD Да, см. Scikit-learn.org/stable/modules/generated/… в самом низу. Установите average=Noneи определите метки, а затем вы получите метрику, которую ищете, для каждой из указанных вами меток.
wonderkid2 02
Есть ли способ получить оценку точности по меткам?
Анкур Синха
@trollster Я не понимаю, о чем ты? Разве не то, что я показываю в ответах на баллы точности по меткам?
wonderkid2
16

Поставленный вопрос

Ответ на вопрос «какую метрику следует использовать для мультиклассовой классификации с несбалансированными данными»: Макро-F1-мера. Также можно использовать Macro Precision и Macro Recall, но их не так легко интерпретировать, как для двоичной классификации, они уже включены в F-меру, а избыточные метрики усложняют сравнение методов, настройку параметров и т. Д.

Микро-усреднение чувствительно к дисбалансу классов: если ваш метод, например, хорошо работает для наиболее распространенных ярлыков и полностью портит другие, микро-усредненные показатели показывают хорошие результаты.

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

Соколова, Марина и Гай Лапальме. «Систематический анализ показателей эффективности для задач классификации». Обработка информации и управление 45.4 (2009): 427-437.

Вопрос по конкретному приложению

Однако, возвращаясь к вашей задаче, я бы исследовал 2 темы:

  1. показатели, обычно используемые для вашей конкретной задачи - они позволяют (а) сравнивать ваш метод с другими и понимать, делаете ли вы что-то не так, и (б) не исследовать это самостоятельно и повторно использовать чужие выводы;
  2. Стоимость различных ошибок ваших методов - например, вариант использования вашего приложения может полагаться только на 4- и 5-звездочные обзоры - в этом случае хорошая метрика должна учитывать только эти 2 метки.

Часто используемые метрики. Изучив литературу, я могу сделать вывод, что есть 2 основных показателя оценки:

  1. Точность , которая используется, например, в

Ю, Эйприл и Дэрил Чанг. «Мультиклассовое прогнозирование настроений с помощью Yelp Business».

( ссылка ) - обратите внимание, что авторы работают практически с одинаковым распределением оценок, см. рисунок 5.

Панг, Бо и Лилиан Ли. «Видеть звезды: использование классовых отношений для категоризации настроений по шкале оценок». Труды 43-го ежегодного собрания ассоциации компьютерной лингвистики. Ассоциация компьютерной лингвистики, 2005.

( ссылка )

  1. MSE (или, реже, Средняя абсолютная ошибка - MAE ) - см., Например,

Ли, Мунтаэ и Р. Графа. «Мультиклассовый анализ настроений с отзывами о ресторанах». Заключительные проекты из CS N 224 (2010).

( ссылка ) - они исследуют как точность, так и MSE, считая последнее лучше

Папас, Николаос, улица Маркони и Андрей Попеску-Белис. «Объясняя звезды: взвешенное множественное обучение для анализа настроений на основе аспектов». Материалы конференции 2014 г. по эмпирическим методам обработки естественного языка. № EPFL-CONF-200899. 2014 г.

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

Стоимость разных ошибок . Если вы больше заботитесь о том, чтобы избежать грубых ошибок, например, присвоить обзор от 1 до 5 или что-то в этом роде, посмотрите MSE; если разница имеет значение, но не так уж и много, попробуйте MAE, так как она не квадратирует разницу; в противном случае оставайтесь с точностью.

О подходах, а не о показателях

Попробуйте подходы регрессии, например SVR , поскольку они обычно превосходят классификаторы Multiclass, такие как SVC или OVA SVM.

Никита Астраханцев
источник
13

Во-первых, немного сложнее использовать простой подсчетный анализ, чтобы определить, являются ли ваши данные несбалансированными или нет. Например: 1 из 1000 положительных наблюдений - это просто шум, ошибка или прорыв в науке? Никогда не знаешь.
Так что всегда лучше использовать все имеющиеся у вас знания и выбирать свой статус со всей мудростью.

Ладно, а если он действительно неуравновешенный?
Еще раз - посмотрите на свои данные. Иногда можно найти одно или два наблюдения, умноженных в сотни раз. Иногда бывает полезно создать фальшивые одноклассные наблюдения.
Если все данные чистые, следующим шагом будет использование весов классов в модели прогнозирования.

Так что насчет метрик мультикласса?
По моему опыту, ни одна из ваших метрик обычно не используется. Есть две основные причины.
Во-первых: всегда лучше работать с вероятностями, чем с твердым прогнозом (потому что как еще вы могли бы разделить модели с прогнозом 0,9 и 0,6, если они обе дают вам один и тот же класс?)
И во-вторых: гораздо проще сравнивать модели прогнозирования и создавать новые те, которые зависят только от одной хорошей метрики.
По моему опыту, я мог бы порекомендовать logloss или MSE (или просто среднеквадратичную ошибку).

Как исправить предупреждения sklearn?
Просто (как заметил Янцзе) перезапишите averageпараметр одним из следующих значений: 'micro'(вычислить показатели глобально), 'macro'(вычислить показатели для каждой метки) или 'weighted'(так же, как макрос, но с автоматическими весами).

f1_score(y_test, prediction, average='weighted')

Все ваши предупреждения пришли после вызова функций метрик со averageзначением по умолчанию, 'binary'которое не подходит для мультиклассового прогнозирования.
Удачи и получайте удовольствие от машинного обучения!

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

Что я бы порекомендовал (в рамках scikit-learn), так это попробовать другие очень мощные инструменты классификации: повышение градиента , случайный лес (мой любимый), KNeighbors и многие другие.

После этого вы можете рассчитать среднее арифметическое или геометрическое между прогнозами, и в большинстве случаев вы получите еще лучший результат.

final_prediction = (KNNprediction * RFprediction) ** 0.5
Влад Миронов
источник
1
> «переключаться между регрессией и классификацией (если классы каким-то образом отсортированы), но это довольно редко» Дело в том: 5> 4> 3> 2> 1. Я предлагаю вам взглянуть на документы для этой задачи - есть множество регрессионных и классификационных подходов к задаче (иногда в одной и той же работе).
Никита Астраханцев
Тогда это даже не мультиклассовая классификация, а простая регрессия.
Влад Миронов
Да, внутренне или с точки зрения машинного обучения, это регрессия, но на последнем этапе мы конвертируем результаты регрессии в метки, так что это мультиклассовая классификация - с точки зрения пользователя или приложения.
Никита Астраханцев