マルチラベル分類器でscikit-learnの相互検証関数を使用する方法


20

5つのクラスがあり、各インスタンスがこれらのクラスの1つ以上に属することができるデータセットでさまざまな分類子をテストしているので、特にscikit-learnのマルチラベル分類子を使用していますsklearn.multiclass.OneVsRestClassifier。次に、を使用して相互検証を実行しsklearn.cross_validation.StratifiedKFoldます。これにより、次のエラーが生成されます。

Traceback (most recent call last):
  File "mlfromcsv.py", line 93, in <module>
    main()
  File "mlfromcsv.py", line 77, in main
    test_classifier_multilabel(svm.LinearSVC(), X, Y, 'Linear Support Vector Machine')
  File "mlfromcsv.py", line 44, in test_classifier_multilabel
    scores = cross_validation.cross_val_score(clf_ml, X, Y_list, cv=cv, score_func=metrics.precision_recall_fscore_support, n_jobs=jobs)
  File "/usr/lib/pymodules/python2.7/sklearn/cross_validation.py", line 1046, in cross_val_score
    X, y = check_arrays(X, y, sparse_format='csr')
  File "/usr/lib/pymodules/python2.7/sklearn/utils/validation.py", line 144, in check_arrays
    size, n_samples))
ValueError: Found array with dim 5. Expected 98816

マルチラベル分類器のトレーニングはクラッシュしませんが、相互検証はクラッシュすることに注意してください。このマルチラベル分類器の相互検証を実行するにはどうすればよいですか?

また、問題を5つの異なる分類器のトレーニングと相互検証に分割する2番目のバージョンも作成しました。これはうまく機能します。

これが私のコードです。機能test_classifier_multilabelは問題を与える機能です。 test_classifier私のもう1つの試みです(問題を5つの分類子と5つの相互検証に分割します)。

import numpy as np
from sklearn import *
from sklearn.multiclass import OneVsRestClassifier
from sklearn.neighbors import KNeighborsClassifier
import time

def test_classifier(clf, X, Y, description, jobs=1):
    print '=== Testing classifier {0} ==='.format(description)
    for class_idx in xrange(Y.shape[1]):
        print ' > Cross-validating for class {:d}'.format(class_idx)
        n_samples = X.shape[0]
        cv = cross_validation.StratifiedKFold(Y[:,class_idx], 3)
        t_start = time.clock()
        scores = cross_validation.cross_val_score(clf, X, Y[:,class_idx], cv=cv, score_func=metrics.precision_recall_fscore_support, n_jobs=jobs)
        t_end = time.clock();
        print 'Cross validation time: {:0.3f}s.'.format(t_end-t_start)
        str_tbl_fmt = '{:>15s}{:>15s}{:>15s}{:>15s}{:>15s}'
        str_tbl_entry_fmt = '{:0.2f} +/- {:0.2f}'
        print str_tbl_fmt.format('', 'Precision', 'Recall', 'F1 score', 'Support')
        for (score_class, lbl) in [(0, 'Negative'), (1, 'Positive')]:
            mean_precision = scores[:,0,score_class].mean()
            std_precision = scores[:,0,score_class].std()
            mean_recall = scores[:,1,score_class].mean()
            std_recall = scores[:,1,score_class].std()
            mean_f1_score = scores[:,2,score_class].mean()
            std_f1_score = scores[:,2,score_class].std()
            support = scores[:,3,score_class].mean()
            print str_tbl_fmt.format(
                lbl,
                str_tbl_entry_fmt.format(mean_precision, std_precision),
                str_tbl_entry_fmt.format(mean_recall, std_recall),
                str_tbl_entry_fmt.format(mean_f1_score, std_f1_score),
                '{:0.2f}'.format(support))

def test_classifier_multilabel(clf, X, Y, description, jobs=1):
    print '=== Testing multi-label classifier {0} ==='.format(description)
    n_samples = X.shape[0]
    Y_list = [value for value in Y.T]
    print 'Y_list[0].shape:', Y_list[0].shape, 'len(Y_list):', len(Y_list)
    cv = cross_validation.StratifiedKFold(Y_list, 3)
    clf_ml = OneVsRestClassifier(clf)
    accuracy = (clf_ml.fit(X, Y).predict(X) != Y).sum()
    print 'Accuracy: {:0.2f}'.format(accuracy)
    scores = cross_validation.cross_val_score(clf_ml, X, Y_list, cv=cv, score_func=metrics.precision_recall_fscore_support, n_jobs=jobs)
    str_tbl_fmt = '{:>15s}{:>15s}{:>15s}{:>15s}{:>15s}'
    str_tbl_entry_fmt = '{:0.2f} +/- {:0.2f}'
    print str_tbl_fmt.format('', 'Precision', 'Recall', 'F1 score', 'Support')
    for (score_class, lbl) in [(0, 'Negative'), (1, 'Positive')]:
        mean_precision = scores[:,0,score_class].mean()
        std_precision = scores[:,0,score_class].std()
        mean_recall = scores[:,1,score_class].mean()
        std_recall = scores[:,1,score_class].std()
        mean_f1_score = scores[:,2,score_class].mean()
        std_f1_score = scores[:,2,score_class].std()
        support = scores[:,3,score_class].mean()
        print str_tbl_fmt.format(
            lbl,
            str_tbl_entry_fmt.format(mean_precision, std_precision),
            str_tbl_entry_fmt.format(mean_recall, std_recall),
            str_tbl_entry_fmt.format(mean_f1_score, std_f1_score),
            '{:0.2f}'.format(support))

def main():
    nfeatures = 13
    nclasses = 5
    ncolumns = nfeatures + nclasses

    data = np.loadtxt('./feature_db.csv', delimiter=',', usecols=range(ncolumns))

    print data, data.shape
    X = np.hstack((data[:,0:3], data[:,(nfeatures-1):nfeatures]))
    print 'X.shape:', X.shape
    Y = data[:,nfeatures:ncolumns]
    print 'Y.shape:', Y.shape

    test_classifier(svm.LinearSVC(), X, Y, 'Linear Support Vector Machine', jobs=-1)
    test_classifier_multilabel(svm.LinearSVC(), X, Y, 'Linear Support Vector Machine')

if  __name__ =='__main__':
    main()

Ubuntu 13.04とscikit-learn 0.12を使用しています。私のデータは、形状(98816、4)および(98816、5)を持つ2つの配列(XおよびY)の形式です。つまり、インスタンスごとに4つの特徴と5つのクラスラベルです。ラベルは1または0で、そのクラス内のメンバーシップを示します。それについてのドキュメントがあまりないので、正しい形式を使用していますか?

回答:


10

階層化サンプリングとは、クラスメンバーシップの分布がKFoldサンプリングで保持されることを意味します。これは、ターゲットベクトルに観測ごとに複数のラベルがある可能性があるマルチラベルの場合、あまり意味がありません。

この意味で、成層化には2つの可能な解釈があります。

ni=1n2n

もう1つのオプションは、ラベルベクトルの分布の確率質量がフォールド全体でほぼ同じになるように、トレーニングデータを試してセグメント化することです。例えば

import numpy as np

np.random.seed(1)
y = np.random.randint(0, 2, (5000, 5))
y = y[np.where(y.sum(axis=1) != 0)[0]]


def proba_mass_split(y, folds=7):
    obs, classes = y.shape
    dist = y.sum(axis=0).astype('float')
    dist /= dist.sum()
    index_list = []
    fold_dist = np.zeros((folds, classes), dtype='float')
    for _ in xrange(folds):
        index_list.append([])
    for i in xrange(obs):
        if i < folds:
            target_fold = i
        else:
            normed_folds = fold_dist.T / fold_dist.sum(axis=1)
            how_off = normed_folds.T - dist
            target_fold = np.argmin(np.dot((y[i] - .5).reshape(1, -1), how_off.T))
        fold_dist[target_fold] += y[i]
        index_list[target_fold].append(i)
    print("Fold distributions are")
    print(fold_dist)
    return index_list

if __name__ == '__main__':
    proba_mass_split(y)

通常のトレーニングを取得するには、KFoldが生成するインデックスをテストするには、np.arange(y.shape [0])で各インデックスのnp.setdiff1dを返すように書き換えてから、iterメソッドでクラスにラップします。


この説明をありがとう。何かを確認したいのですがOneVsRestClassifier、2D配列(たとえばy、サンプルコード)またはクラスラベルのリストのタプルを受け入れますか?scikit-learnのマルチラベル分類の例を今見て、make_multilabel_classification関数がクラスラベルのリストのタプルを返すのを見たので、私は尋ね([2], [0], [0, 2], [0]...)ます。
チップパイ

2
両方の方法で機能します。タプルのリストが渡されると、sklearn.preprocessing.LabelBinarizerがそれに適合します。いくつかのアルゴリズムがマルチクラスマルチラベルの場合に機能することを知っています。特にRandomForest。
ジェシカミック

どうもありがとう、これで少なくともクラッシュを乗り越えることができた。今のところ、K-fold cross validationに切り替えましたが、すぐにコードを使用すると思います。ただし、cross_val_scoreによって返されるスコアには2つの列しかありません。つまり、クラスが2つしかないかのようになります。に変更するとmetrics.confusion_matrix、2x2の混同行列が生成されます。メトリックのいずれかがマルチラベル分類子をサポートしていますか?
チップパイ

私自身のサブ質問に答えました。マルチラベル分類子をサポートするメトリックはscikit-learn 0.14-rcにのみ登場したため、その機能が必要な場合は自分でアップグレードする必要があります。ヘルプとコードをありがとう。
チップパイ

returnステートメントの配列を削除しました。完全に分割されたデータポイントのセットが常に見つかる理由はありません。これがうまくいくかどうか教えてください。また、コードにいくつかのテストを記述する必要があります。凸型最適化アルゴリズムを終日見つめた後、このアルゴリズムを使いました。
ジェシカミック

3

あなたはチェックしたいかもしれません:マルチラベルデータの層別化について

ここでは、著者は最初に一意のラベルセットからサンプリングするという簡単なアイデアを伝え、次にマルチラベルデータセットの新しいアプローチの反復成層法を紹介します。

反復成層法のアプローチは貪欲です。

概要を簡単に説明するために、反復成層法の機能を次に示します。

最初に、kフォールドのそれぞれにいくつの例が入るべきかを見つけます。

  • ijcij

  • lDl

  • Dlkckjll

  • kc

主なアイデアは、まずまれなラベルに焦点を当てることです。このアイデアは、

「まれなラベルが優先的に検査されない場合、それらは望ましくない方法で配布される可能性があり、これはその後修復できません」

関係がどのように破られるか、およびその他の詳細を理解するために、論文を読むことをお勧めします。また、実験セクションから理解できることは、ラベルセット/例の比率に応じて、一意のラベルセットベースまたはこの提案された反復成層法を使用することです。この比率の値が低い場合、折り畳み全体のラベルの分布は、いくつかのケースで反復成層法に近いか、より良いです。この比率の値が高い場合、反復成層法は、折り畳みでより良い分布を維持していることが示されます。


1
前述の論文のPDFへのリンク:lpis.csd.auth.gr/publications/sechidis-ecmlpkdd-2011.pdf
Temak
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.