web-dev-qa-db-fra.com

Quelle est la différence entre OneVsRestClassifier et MultiOutputClassifier dans scikit learn?

Quelqu'un peut-il expliquer (avec un exemple peut-être) quelle est la différence entre OneVsRestClassifier et MultiOutputClassifier dans scikit-learn?

J'ai lu la documentation et j'ai compris que nous utilisons:

  • OneVsRestClassifier - lorsque nous voulons effectuer une classification multiclasse ou multilabel et que sa stratégie consiste en ajustement d'un classificateur par classe. Pour chaque classificateur, la classe est adaptée à toutes les autres classes. (C'est assez clair et cela signifie que le problème de la classification multiclasse/multilabel est décomposé en plusieurs problèmes de classification binaire).
  • MultiOutputClassifier - quand nous voulons faire une classification multi-cible (qu'est-ce que c'est?) Et sa stratégie consiste en ajustant un classificateur par cible (que signifie cible là?)

J'ai déjà utilisé OneVsRestClassifier pour la classification multi-étiquettes et je peux comprendre comment cela fonctionne, mais j'ai trouvé MultiOutputClassifier et je ne comprends pas comment cela fonctionne différemment de OneVsRestClassifier.

23
delusionX

Classification multiclasse

Pour mieux illustrer les différences, supposons que votre objectif est de classer SO questions en n_classes classes différentes, mutuellement exclusives. Par souci de simplicité dans cet exemple, nous ne considérerons que quatre classes, à savoir 'Python', 'Java', 'C++' et 'Other language'. Supposons que vous ayez un ensemble de données formé de seulement six SO questions, et les étiquettes de classe de ces questions sont stockées dans un tableau y comme suit:

import numpy as np
y = np.asarray(['Java', 'C++', 'Other language', 'Python', 'C++', 'Python'])

La situation décrite ci-dessus est généralement appelée classification multiclasse (également connue sous le nom de classification multinomiale). Afin d'adapter le classificateur et de valider le modèle via la bibliothèque scikit-learn, vous devez transformer les étiquettes de classe de texte en étiquettes numériques. Pour ce faire, vous pouvez utiliser LabelEncoder :

from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
y_numeric = le.fit_transform(y)

Voici comment les étiquettes de votre jeu de données sont encodées:

In [220]: y_numeric
Out[220]: array([1, 0, 2, 3, 0, 3], dtype=int64)

où ces nombres désignent des indices du tableau suivant:

In [221]: le.classes_
Out[221]: 
array(['C++', 'Java', 'Other language', 'Python'], 
      dtype='|S14')

Un cas particulier important est celui où il n'y a que deux classes, c'est-à-dire n_classes = 2. Ceci est généralement appelé classification binaire .

Classification multi-étiquettes

Supposons maintenant que vous souhaitiez effectuer une telle classification multiclasse en utilisant un pool de n_classes classificateurs binaires, étant n_classes le nombre de classes différentes. Chacun de ces classificateurs binaires décide si un élément appartient à une classe spécifique ou non. Dans ce cas, vous ne pouvez pas coder les étiquettes de classe sous forme de nombres entiers à partir de 0 à n_classes - 1, vous devez plutôt créer une matrice d'indicateur bidimensionnelle. Considérez que l'exemple n est de classe k. Puis le [n, k] l'entrée de la matrice des indicateurs est 1 et le reste des éléments de la ligne n sont 0. Il est important de noter que si les classes ne s'excluent pas mutuellement, il peut y avoir plusieurs 1 est dans une rangée. Cette approche est nommée classification multi-étiquettes et peut être facilement implémentée via MultiLabelBinarizer :

from sklearn.preprocessing import MultiLabelBinarizer
mlb = MultiLabelBinarizer()
y_indicator = mlb.fit_transform(y[:, None])

L'indicateur ressemble à ceci:

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]])

et les numéros de colonne où 1 sont en fait des indices de ce tableau:

In [226]: mlb.classes_
Out[226]: array(['C++', 'Java', 'Other language', 'Python'], dtype=object)

Classification multi-sorties

Que se passe-t-il si vous souhaitez classer une question particulière SO en fonction de deux critères différents simultanément, par exemple la langue et l'application? Dans ce cas, vous avez l'intention de faire une classification multi-sorties . Par souci de simplicité, je ne considérerai que trois classes d'application, à savoir 'Computer Vision', 'Speech Processing' et 'Other application '. Le tableau d'étiquettes de votre jeu de données doit être bidimensionnel:

y2 = np.asarray([['Java', 'Computer Vision'],
                 ['C++', 'Speech Recognition'],
                 ['Other language', 'Computer Vision'],
                 ['Python', 'Other Application'],
                 ['C++', 'Speech Recognition'],
                 ['Python', 'Computer Vision']])

Encore une fois, nous devons transformer les étiquettes de classe de texte en étiquettes numériques. Pour autant que je sache, cette fonctionnalité n'est pas encore implémentée dans scikit-learn, vous devrez donc écrire votre propre code. Ce fil décrit quelques façons intelligentes de le faire, mais pour les besoins de ce post, le one-liner suivant devrait suffire:

y_multi = np.vstack((le.fit_transform(y2[:, i]) for i in range(y2.shape[1]))).T

Les étiquettes codées ressemblent à ceci:

In [229]: y_multi
Out[229]: 
array([[1, 0],
       [0, 2],
       [2, 0],
       [3, 1],
       [0, 2],
       [3, 0]], dtype=int64)

Et la signification des valeurs dans chaque colonne peut être déduite des tableaux suivants:

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')
25
Tonechas