В чем разница между OneVsRestClassifier и MultiOutputClassifier в обучении scikit?
Может кто-нибудь объяснить (с примером, может быть), в чем разница между OneVsRestClassifier и MultiOutputClassifier в scikit-learn?
Я прочитал документацию и понял, что мы используем:
- OneVsRestClassifier - когда мы хотим сделать мультиклассовую или мультиметочную классификацию, и ее стратегия состоит в подборе одного классификатора на класс. Для каждого классификатора класс сопоставляется со всеми другими классами. (Это довольно ясно, и это означает, что проблема многоклассовой / многоклавишной классификации разбита на множественные проблемы двоичной классификации).
- MultiOutputClassifier - когда мы хотим выполнить многоцелевую классификацию (что это?) И ее стратегия состоит в том, чтобы подогнать по одному классификатору для каждой цели (что там означает цель?)
Я уже использовал OneVsRestClassifier для многослойной классификации, и я могу понять, как он работает, но потом я нашел MultiOutputClassifier и не могу понять, как он работает иначе, чем OneVsRestClassifier.
3 ответа
Мультиклассовая классификация
Чтобы лучше проиллюстрировать различия, давайте предположим, что ваша цель состоит в классификации вопросов SO в n_classes
разные, взаимоисключающие классы. Для простоты в этом примере мы рассмотрим только четыре класса, а именно 'Python'
, 'Java'
, 'C++'
а также 'Other language'
, Предположим, что у вас есть набор данных, сформированный всего из шести вопросов SO, а метки классов этих вопросов хранятся в массиве. y
следующее:
import numpy as np
y = np.asarray(['Java', 'C++', 'Other language', 'Python', 'C++', 'Python'])
Описанная выше ситуация обычно называется мультиклассовой классификацией (также известной как мультиномиальная классификация). Чтобы соответствовать классификатору и проверить модель с помощью библиотеки scikit-learn, необходимо преобразовать метки текстовых классов в числовые метки. Для этого вы можете использовать LabelEncoder:
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
y_numeric = le.fit_transform(y)
Вот как кодируются метки вашего набора данных:
In [220]: y_numeric
Out[220]: array([1, 0, 2, 3, 0, 3], dtype=int64)
где эти числа обозначают индексы следующего массива:
In [221]: le.classes_
Out[221]:
array(['C++', 'Java', 'Other language', 'Python'],
dtype='|S14')
Важный частный случай, когда есть только два класса, т.е. n_classes = 2
, Это обычно называется бинарной классификацией.
Многослойная классификация
Давайте теперь предположим, что вы хотите выполнить такую мультиклассовую классификацию, используя пул n_classes
двоичные классификаторы, являющиеся n_classes
количество разных классов. Каждый из этих двоичных классификаторов принимает решение о том, принадлежит ли элемент определенному классу или нет. В этом случае вы не можете кодировать метки классов как целые числа из 0
в n_classes - 1
, вам нужно вместо этого создать двумерную матрицу индикаторов. Рассмотрим этот образец n
имеет класс k
, Затем [n, k]
Ввод матрицы индикатора 1
а остальные элементы в ряду n
являются 0
, Важно отметить, что если классы не являются взаимоисключающими, может быть несколько 1
в ряд. Этот подход называется многослойной классификацией и может быть легко реализован с помощью MultiLabelBinarizer:
from sklearn.preprocessing import MultiLabelBinarizer
mlb = MultiLabelBinarizer()
y_indicator = mlb.fit_transform(y[:, None])
Индикатор выглядит так:
In [225]: y_indicator
Out[225]:
array([[0, 1, 0, 0],
[1, 0, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
[1, 0, 0, 0],
[0, 0, 0, 1]])
и номера столбцов, где 1
На самом деле это индексы этого массива:
In [226]: mlb.classes_
Out[226]: array(['C++', 'Java', 'Other language', 'Python'], dtype=object)
Multioutput классификация
Что если вы хотите классифицировать конкретный вопрос SO по двум различным критериям одновременно, например, язык и приложение? В этом случае вы намереваетесь выполнить многопотоковую классификацию. Для простоты я рассмотрю только три класса приложений, а именно 'Computer Vision'
, 'Speech Processing
' а также 'Other application
". Массив меток вашего набора данных должен быть двухмерным:
y2 = np.asarray([['Java', 'Computer Vision'],
['C++', 'Speech Recognition'],
['Other language', 'Computer Vision'],
['Python', 'Other Application'],
['C++', 'Speech Recognition'],
['Python', 'Computer Vision']])
Опять же, нам нужно преобразовать метки текстовых классов в числовые метки. Насколько я знаю, эта функциональность еще не реализована в scikit-learn, поэтому вам нужно будет написать собственный код. В этой теме описываются некоторые умные способы сделать это, но для целей этого поста должно быть достаточно одной строки:
y_multi = np.vstack((le.fit_transform(y2[:, i]) for i in range(y2.shape[1]))).T
Закодированные метки выглядят так:
In [229]: y_multi
Out[229]:
array([[1, 0],
[0, 2],
[2, 0],
[3, 1],
[0, 2],
[3, 0]], dtype=int64)
И значение значений в каждом столбце может быть выведено из следующих массивов:
In [230]: le.fit(y2[:, 0]).classes_
Out[230]:
array(['C++', 'Java', 'Other language', 'Python'],
dtype='|S18')
In [231]: le.fit(y2[:, 1]).classes_
Out[231]:
array(['Computer Vision', 'Other Application', 'Speech Recognition'],
dtype='|S18')
Это расширение ответа @tonechas. Прочитайте этот ответ, прежде чем читать это. OVR поддерживает Multilabel только в том случае, если каждая метка является бинарной меткой/классом (также называемой бинарной мультиметкой), т. е. либо образец принадлежит этой метке, либо нет. Это не будет работать, когда целью является мультивывод (также называемый мультиклассовой мультиметкой), т.е. когда каждый образец может принадлежать любому одному классу в пределах метки. В последнем случае вам нужно использовать классификатор sklearn Multioutput.
Другими словами, sklearn OVR не работает, когда ваша целевая переменная выглядит так:
y_true = np.arr([[2, 1, 0],
[0, 2, 1],
[1, 2, 4]])
где label1 имеет 4 класса [0, 1, 2, 3]; label2 имеет 3 класса [0, 1, 2]; label3 имеет 5 классов [0, 1, 2, 3, 4]. Пример: первый образец принадлежит классу 2 в метке1, классу 1 в метке2, классу 0 в метке3. Думайте об этом как о том, что метки НЕ являются взаимоисключающими, тогда как классы внутри каждой метки являются взаимоисключающими.
Sklearn OVR будет работать, когда
y_true = np.arr([[0, 1, 1],
[0, 0, 1],
[1, 1, 0]])
где метка1, метка2, метка3 имеют только по 2 класса. Таким образом, образец либо принадлежит этому лейблу, либо нет. Пример: первый образец принадлежит label1 и label2.
Мне жаль, что я не смог найти реальный пример для такого варианта использования.
Есть ответы по этому поводу? Принятый ответ просто описывает концепции, но на самом деле явно не отвечает на вопрос OP: «В чем разница между классами sklearn OneVsRestClassifier и MultiOutputClassifier».
думаю автор вопроса ответил сам себе
MultiOutputClassifier — когда мы хотим выполнить многоцелевую классификацию (что это?), и ее стратегия состоит в установке одного классификатора на каждую цель (что там означает цель?)
цель Y (зависимая переменная)
PS MultiClass или MultiLabel - означает "мульти"-номинальные функции - которые считаются X , которые являются независимыми переменными... (либо multi in rows, либо в feature_columns.count>1 соответственно)
pps Я полагаю, что для каждой цели внутри библиотеки sklearn есть отдельное обучение (подгонка) - относительно цитаты автора