web-dev-qa-db-ja.com

Python:混同行列を正規化する方法?

Sklearnパッケージのconfusion_matrix()メソッドを使用して、分類子の混同行列を計算しました。混同行列の対角要素は、予測ラベルが真のラベルと等しい点の数を表しますが、非対角要素は、分類子によって誤ってラベル付けされた要素です。

混同行列を正規化して、0〜1の数値のみが含まれるようにします。行列から正しく分類されたサンプルの割合を読み取ります。

行列を正規化する方法(行と列の正規化)をいくつかの方法で見つけましたが、数学についてはあまり知らないため、これが正しいアプローチであるかどうかはわかりません。誰かが助けてくれますか?

26
Kaly

M[i,j] を意味する Element of real class i was classified as j。それとは逆の場合、私が言うすべてを転置する必要があります。具体的な例として、次のマトリックスも使用します。

1 2 3
4 5 6
7 8 9

基本的に、次の2つのことができます。

各クラスの分類方法を見つける

最初に尋ねることができるのは、実際のクラスiの要素の何パーセントがここでは各クラスとして分類されるかです。そのためには、iを修正する行を取得し、各要素をその行の要素の合計で割ります。この例では、クラス2のオブジェクトはクラス1として4回分類され、クラス2として5回正しく分類され、クラス3として6回分類されます。パーセンテージを見つけるには、すべてを合計4 + 5 + 6 = 15で割ります。

4/15 of the class 2 objects are classified as class 1
5/15 of the class 2 objects are classified as class 2
6/15 of the class 2 objects are classified as class 3

各分類の原因となっているクラスを見つける

2番目にできることは、分類子からの各結果を見て、それらの結果の数が実際の各クラスから発生していることを確認することです。それは他のケースと似ていますが、行ではなく列があります。この例では、元のクラスが1の場合、分類子は「1」を1回返します。元のクラスが2の場合は4回、元のクラスが3の場合は7回です。パーセンテージを見つけるには、合計1 + 4 + 7 = 12

1/12 of the objects classified as class 1 were from class 1
4/12 of the objects classified as class 1 were from class 2
7/12 of the objects classified as class 1 were from class 3

-

もちろん、私が与えた方法は両方とも一度に1つの行の列にのみ適用され、この形式で実際に混同行列を変更することが良いアイデアかどうかはわかりません。ただし、これはあなたが探しているパーセンテージを与えるはずです。

8
hugomg

仮定

>>> y_true = [0, 0, 1, 1, 2, 0, 1]
>>> y_pred = [0, 1, 0, 1, 2, 2, 1]
>>> C = confusion_matrix(y_true, y_pred)
>>> C
array([[1, 1, 1],
       [1, 2, 0],
       [0, 0, 1]])

次に、クラスごとに適切なラベルを受け取ったサンプルの数を調べるには、

>>> C / C.astype(np.float).sum(axis=1)
array([[ 0.33333333,  0.33333333,  1.        ],
       [ 0.33333333,  0.66666667,  0.        ],
       [ 0.        ,  0.        ,  1.        ]])

対角線には必要な値が含まれています。これらを計算するもう1つの方法は、計算しているのがクラスごとのリコールであることを認識することです。

>>> from sklearn.metrics import precision_recall_fscore_support
>>> _, recall, _, _ = precision_recall_fscore_support(y_true, y_pred)
>>> recall
array([ 0.33333333,  0.66666667,  1.        ])

同様に、axis=0の合計で除算すると、精度(グラウンドトゥルースラベルkを持つclass -k予測の一部)が得られます。

>>> C / C.astype(np.float).sum(axis=0)
array([[ 0.5       ,  0.33333333,  0.5       ],
       [ 0.5       ,  0.66666667,  0.        ],
       [ 0.        ,  0.        ,  0.5       ]])
>>> prec, _, _, _ = precision_recall_fscore_support(y_true, y_pred)
>>> prec
array([ 0.5       ,  0.66666667,  0.5       ])
20
Fred Foo

Sklearnドキュメントから ((plot example)

cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]

ここで、cmはsklearnによって提供される混同行列です。

7
Antoni

Sklearnのconfusion_matrix()が出力する行列は など

C_ {i、j}は、グループiにあることがわかっているが、グループjにあると予測されている観測値の数に等しい

したがって、各クラスのパーセンテージ(バイナリ分類では特異性と感度と呼ばれることが多い)を取得するには、行で正規化する必要があります。行の各要素を、その行の要素の合計で割った値で置き換えます。

Sklearnには、混乱行列からメトリックを計算する使用可能な要約関数があります: classification_report 。特異度や感度ではなく、精度と再現率を出力しますが、それらは一般的に(特に、不均衡なマルチクラス分類の場合)より有益であると見なされることがよくあります。

7
damienfrancois

グラフをプロットするためにscikit-learn自体が提供するライブラリがあります。これはmatplotlibに基づいており、先に進むにはすでにインストールされているはずです。

pip install scikit-plot

normalizeパラメータをtrueに設定するだけです:

import scikitplot as skplt 
skplt.metrics.plot_confusion_matrix(Y_TRUE, Y_PRED, normalize=True)
0
Pranzell

これを行う最も簡単な方法は、次のようにすることだと思います。

c = sklearn.metrics.confusion_matrix(y, y_pred)
normed_c = (c.T / c.astype(np.float).sum(axis=1)).T
0

Seabornを使用すると、ヒースマップを使用して正規化されたかなり混同した行列を簡単に印刷できます。

enter image description here

from sklearn.metrics import confusion_matrix
import seaborn as sns

cm = confusion_matrix(y_test, y_pred)
# Normalise
cmn = cm.astype('float') / 
cm.sum(axis=1)[:, np.newaxis]
fig, ax = plt.subplots(figsize=(10,10))
sns.heatmap(cmn, annot=True, fmt='.2f', xticklabels=target_names, yticklabels=target_names)
plt.ylabel('Actual')
plt.xlabel('Predicted')
plt.show(block=False)