Cách sử dụng các chức năng xác thực chéo của scikit-learn trên các trình phân loại đa nhãn


20

Tôi đang kiểm tra các trình phân loại khác nhau trên một tập dữ liệu có 5 lớp và mỗi trường hợp có thể thuộc về một hoặc nhiều lớp trong số đó, vì vậy, tôi đang sử dụng các trình phân loại đa nhãn của scikit-learn, cụ thể sklearn.multiclass.OneVsRestClassifier. Bây giờ tôi muốn thực hiện xác nhận chéo bằng cách sử dụng sklearn.cross_validation.StratifiedKFold. Điều này tạo ra lỗi sau:

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

Lưu ý rằng đào tạo trình phân loại đa nhãn không bị sập, nhưng xác thực chéo thì có. Làm cách nào để thực hiện xác thực chéo cho trình phân loại nhiều nhãn này?

Tôi cũng đã viết một phiên bản thứ hai phân tích vấn đề thành đào tạo và xác nhận hợp lệ 5 phân loại riêng biệt. Điều này chỉ hoạt động tốt.

Đây là mã của tôi. Các chức năng test_classifier_multilabellà một trong những vấn đề. test_classifierlà nỗ lực khác của tôi (chia vấn đề thành 5 phân loại và 5 xác nhận chéo).

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

Tôi đang sử dụng Ubuntu 13.04 và scikit-learn 0.12. Dữ liệu của tôi ở dạng hai mảng (X và Y) có hình dạng (98816, 4) và (98816, 5), tức là 4 tính năng cho mỗi phiên bản và 5 nhãn lớp. Các nhãn là 1 hoặc 0 cho thành viên được chỉ định trong lớp đó. Tôi có đang sử dụng định dạng đúng vì tôi không thấy nhiều tài liệu về điều đó?

Câu trả lời:


10

Lấy mẫu phân tầng có nghĩa là phân phối thành viên lớp được bảo toàn trong mẫu KFold của bạn. Điều này không có nhiều ý nghĩa trong trường hợp đa nhãn trong đó vectơ đích của bạn có thể có nhiều hơn một nhãn cho mỗi lần quan sát.

Có hai cách giải thích có thể phân tầng theo nghĩa này.

Đối với nhãn trong đó có ít nhất một trong số chúng được điền sẽ cung cấp cho bạn nhãn duy nhất. Bạn có thể thực hiện lấy mẫu phân tầng trên mỗi thùng nhãn duy nhất.n i = 1 2 nnΣtôi= =1n2n

Tùy chọn khác là thử và phân đoạn dữ liệu huấn luyện mà khối lượng xác suất phân phối của các vectơ nhãn xấp xỉ nhau qua các nếp gấp. Ví dụ

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)

Để được đào tạo bình thường, các chỉ số kiểm tra mà KFold tạo ra bạn muốn viết lại nó cho nó trả về np.setdiff1d của mỗi chỉ mục bằng np.arange (y.shape [0]), sau đó bọc nó trong một lớp bằng phương thức lặp .


Cảm ơn lời giải thích này. Tôi chỉ muốn kiểm tra một cái gì đó, liệu có OneVsRestClassifierchấp nhận một mảng 2D (ví dụ như ytrong mã ví dụ của bạn) hoặc một bộ danh sách các nhãn lớp không? Tôi hỏi bởi vì tôi đã xem ví dụ phân loại đa nhãn trên scikit-learn vừa rồi và thấy rằng make_multilabel_classificationhàm trả về một danh sách các danh sách nhãn lớp, ví dụ như ([2], [0], [0, 2], [0]...)khi sử dụng 3 lớp?
chippies

2
Nó hoạt động cả hai cách. Khi một danh sách các bộ dữ liệu được thông qua, nó phù hợp với sklearn.pre Processing.LabelBinarizer cho nó. Bạn biết một số thuật toán hoạt động trong trường hợp đa nhãn. Đáng chú ý là RandomForest.
Jessica Mick

Cảm ơn rất nhiều, điều này ít nhất đã giúp tôi vượt qua các vụ tai nạn. Hiện tại tôi đã chuyển sang xác thực chéo K-Fold nhưng tôi nghĩ rằng tôi sẽ sớm sử dụng mã của bạn. Tuy nhiên, bây giờ, điểm được trả về bởi cross_val_score chỉ có hai cột, tức là như thể chỉ có hai lớp. Thay đổi để metrics.confusion_matrixtạo ma trận nhầm lẫn 2x2. Có bất kỳ số liệu hỗ trợ phân loại đa nhãn?
chippies

Tôi đã trả lời câu hỏi phụ của riêng tôi. Các số liệu hỗ trợ trình phân loại đa nhãn chỉ xuất hiện trong scikit-learn 0.14-rc, vì vậy tôi sẽ phải nâng cấp nếu tôi muốn khả năng đó hoặc tự mình làm điều đó. Cảm ơn sự giúp đỡ và mã.
chippies

Tôi loại bỏ mảng trên câu lệnh return. Không có lý do gì mà bạn sẽ luôn tìm thấy một tập hợp các điểm dữ liệu được phân vùng hoàn hảo. Hãy cho tôi biết nếu điều này làm việc ra. Bạn cũng nên viết một số bài kiểm tra trong mã của bạn. Tôi đã thở ra thuật toán này sau khi nhìn chằm chằm vào các thuật toán tối ưu hóa lồi cả ngày.
Jessica Mick

3

Bạn có thể muốn kiểm tra: Về sự phân tầng dữ liệu đa nhãn .

Ở đây, các tác giả trước tiên cho biết ý tưởng đơn giản về lấy mẫu từ các nhãn duy nhất và sau đó giới thiệu một cách tiếp cận phân tầng lặp mới cho các bộ dữ liệu đa nhãn.

Cách tiếp cận của phân tầng lặp là tham lam.

Để biết tổng quan nhanh, đây là những gì phân tầng lặp lại:

Đầu tiên, họ tìm ra có bao nhiêu ví dụ nên đi vào mỗi nếp gấp k.

  • tôijctôij

  • tôiDtôi

  • Dtôikckjtôitôi

  • kc

Ý tưởng chính là trước tiên tập trung vào các nhãn hiếm, ý tưởng này xuất phát từ giả thuyết rằng

"nếu các nhãn hiếm không được kiểm tra ưu tiên, thì chúng có thể được phân phối theo cách không mong muốn và điều này không thể được sửa chữa sau đó"

Để hiểu làm thế nào mối quan hệ bị phá vỡ và các chi tiết khác, tôi sẽ khuyên bạn nên đọc bài báo. Ngoài ra, từ phần thí nghiệm những gì tôi có thể hiểu là, tùy thuộc vào tỷ lệ nhãn / ví dụ người ta có thể muốn sử dụng nhãn duy nhất dựa trên phương pháp phân tầng lặp được đề xuất này. Đối với các giá trị thấp hơn của tỷ lệ này, sự phân phối các nhãn trên các nếp gấp gần hoặc tốt hơn trong một vài trường hợp là phân tầng lặp. Đối với các giá trị cao hơn của tỷ lệ này, phân tầng lặp được hiển thị để duy trì phân phối tốt hơn trong các nếp gấp.


1
liên kết đến bản PDF của bài báo được đề cập: lpis.csd.auth.gr/publications/sechidis-ecmlpkdd-2011.pdf
Temak
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.