web-dev-qa-db-ja.com

scikit learnのOneVsRestClassifierとMultiOutputClassifierの違いは何ですか?

誰かが(おそらく多分例を挙げて) OneVsRestClassifierMultiOutputClassifierdifferenceの違いを説明してもらえますかscikit-learn?

私はドキュメントを読んで、私たちが使用していることを理解しました:

  • OneVsRestClassifier-マルチクラスまたはマルチラベル分類を行いたい場合、その戦略はで構成されますクラスごとに1つの分類子をフィッティングする。各分類子について、クラスは他のすべてのクラスに対して適合されます。 (これは非常に明確であり、マルチクラス/マルチラベル分類の問題が複数のバイナリ分類問題に分解されることを意味します)。
  • MultiOutputClassifier-マルチターゲット分類を行いたい場合(これは何ですか?)、その戦略はターゲットごとに1つの分類子を適合する(そこでターゲットはどういう意味ですか?)

私はすでにマルチラベル分類にOneVsRestClassifierを使用しており、それがどのように機能するかを理解できますが、その後MultiOutputClassifierを見つけ、OneVsRestClassifierとどのように機能するかを理解できません。

23
delusionX

マルチクラス分類

違いをよりわかりやすく説明するために、SOの質問をn_classesの異なる相互に排他的なクラスに分類することが目標であると仮定しましょう。この例では簡単にするために、4つのクラス、つまり'Python''Java''C++'、および'Other language'のみを検討します。 6つのSO質問で構成されるデータセットがあり、それらの質問のクラスラベルが配列yに次のように格納されていると仮定します。

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

上記の状況は通常、multiclass Classification(多項分類とも呼ばれます)と呼ばれます。 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')

重要な特定のケースは、クラスが2つしかない場合、つまりn_classes = 2です。これは通常バイナリ分類と呼ばれます。

マルチラベル分類

n_classesバイナリ分類子のプールを使用して、そのようなマルチクラス分類を実行するとします。これはn_classesさまざまなクラスの数です。これらの各バイナリ分類子は、アイテムが特定のクラスであるかどうかを判断します。この場合、クラスラベルを0からn_classes - 1の整数としてエンコードできないため、代わりに2次元インジケーターマトリックスを作成する必要があります。サンプルnはクラスkであると考えてください。次に、インジケータマトリックスの[n, k]エントリは1で、行nの残りの要素は0です。クラスが相互に排他的でない場合、複数の1が連続する可能性があることに注意することが重要です。このアプローチの名前はmultilabel Classificationで、 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)

多出力分類

特定のSO質問を、たとえば言語とアプリケーションなどの2つの異なる基準に従って同時に分類する場合はどうでしょうか。この場合、複数出力分類を実行する予定です。簡単にするために、'Computer Vision''Speech Processing '、および'Other application'という3つのアプリケーションクラスのみを検討します。データセットのラベル配列は2次元である必要があります。

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