Bagaimana cara menghitung presisi, recall, akurasi, dan skor f1 untuk kasus multiclass dengan scikit learn?

109

Saya sedang mengerjakan masalah analisis sentimen, datanya terlihat seperti ini:

label instances
    5    1190
    4     838
    3     239
    1     204
    2     127

Jadi data saya tidak seimbang sejak 1190 instancesdiberi label 5. Untuk klasifikasi saya menggunakan SVC scikit . Masalahnya adalah saya tidak tahu bagaimana menyeimbangkan data saya dengan cara yang benar untuk menghitung secara akurat presisi, perolehan, akurasi, dan skor f1 untuk casing multikelas. Jadi saya mencoba pendekatan berikut:

Pertama:

    wclf = SVC(kernel='linear', C= 1, class_weight={1: 10})
    wclf.fit(X, y)
    weighted_prediction = wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, weighted_prediction)
print 'F1 score:', f1_score(y_test, weighted_prediction,average='weighted')
print 'Recall:', recall_score(y_test, weighted_prediction,
                              average='weighted')
print 'Precision:', precision_score(y_test, weighted_prediction,
                                    average='weighted')
print '\n clasification report:\n', classification_report(y_test, weighted_prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, weighted_prediction)

Kedua:

auto_wclf = SVC(kernel='linear', C= 1, class_weight='auto')
auto_wclf.fit(X, y)
auto_weighted_prediction = auto_wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, auto_weighted_prediction)

print 'F1 score:', f1_score(y_test, auto_weighted_prediction,
                            average='weighted')

print 'Recall:', recall_score(y_test, auto_weighted_prediction,
                              average='weighted')

print 'Precision:', precision_score(y_test, auto_weighted_prediction,
                                    average='weighted')

print '\n clasification report:\n', classification_report(y_test,auto_weighted_prediction)

print '\n confussion matrix:\n',confusion_matrix(y_test, auto_weighted_prediction)

Ketiga:

clf = SVC(kernel='linear', C= 1)
clf.fit(X, y)
prediction = clf.predict(X_test)


from sklearn.metrics import precision_score, \
    recall_score, confusion_matrix, classification_report, \
    accuracy_score, f1_score

print 'Accuracy:', accuracy_score(y_test, prediction)
print 'F1 score:', f1_score(y_test, prediction)
print 'Recall:', recall_score(y_test, prediction)
print 'Precision:', precision_score(y_test, prediction)
print '\n clasification report:\n', classification_report(y_test,prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, prediction)


F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1082: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
 0.930416613529

Namun, saya mendapatkan peringatan seperti ini:

/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172:
DeprecationWarning: The default `weighted` averaging is deprecated,
and from version 0.18, use of precision, recall or F-score with 
multiclass or multilabel data or pos_label=None will result in an 
exception. Please set an explicit value for `average`, one of (None, 
'micro', 'macro', 'weighted', 'samples'). In cross validation use, for 
instance, scoring="f1_weighted" instead of scoring="f1"

Bagaimana saya bisa menangani dengan benar data saya yang tidak seimbang untuk menghitung dengan cara yang benar metrik pengklasifikasi?

new_with_python
sumber
Jadi mengapa tidak menambahkan averageparameter dalam kasus ketiga?
yangjie
1
@yangjie saya tidak tahu. Saya baru saja memeriksa dokumentasinya tetapi saya tidak mengerti bagaimana menggunakan metrik dengan benar untuk data yang tidak seimbang. Bisakah Anda memberikan penjelasan yang lebih luas dan contoh ?. Terima kasih!
new_with_python

Jawaban:

164

Saya pikir ada banyak kebingungan tentang bobot mana yang digunakan untuk apa. Saya tidak yakin saya tahu persis apa yang mengganggu Anda jadi saya akan membahas topik yang berbeda, bersabarlah;).

Bobot kelas

Bobot dari class_weightparameter digunakan untuk melatih pengklasifikasi . Mereka tidak digunakan dalam penghitungan metrik mana pun yang Anda gunakan : dengan bobot kelas yang berbeda, angkanya akan berbeda hanya karena pengklasifikasi berbeda.

Pada dasarnya di setiap pengklasifikasi scikit-learn, bobot kelas digunakan untuk memberi tahu model Anda betapa pentingnya sebuah kelas. Artinya, selama pelatihan, pengklasifikasi akan melakukan upaya ekstra untuk mengklasifikasikan kelas dengan bobot tinggi dengan benar.
Cara mereka melakukannya tergantung pada algoritme. Jika Anda menginginkan detail tentang cara kerjanya untuk SVC dan dokumen tersebut tidak masuk akal bagi Anda, silakan sebutkan.

Metriknya

Setelah Anda memiliki pengklasifikasi, Anda ingin mengetahui seberapa baik kinerjanya. Di sini Anda dapat menggunakan metrik yang Anda sebutkan: accuracy, recall_score, f1_score...

Biasanya ketika distribusi kelas tidak seimbang, akurasi dianggap sebagai pilihan yang buruk karena memberikan skor tinggi untuk model yang hanya memprediksi kelas yang paling sering.

Saya tidak akan merinci semua metrik ini tetapi perhatikan bahwa, dengan pengecualian accuracy, metrik tersebut secara alami diterapkan di tingkat kelas: seperti yang Anda lihat di printlaporan klasifikasi ini, metrik tersebut ditentukan untuk setiap kelas. Mereka mengandalkan konsep seperti true positivesatau false negativeyang membutuhkan definisi kelas mana yang positif .

             precision    recall  f1-score   support

          0       0.65      1.00      0.79        17
          1       0.57      0.75      0.65        16
          2       0.33      0.06      0.10        17
avg / total       0.52      0.60      0.51        50

Peringatan

F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The 
default `weighted` averaging is deprecated, and from version 0.18, 
use of precision, recall or F-score with multiclass or multilabel data  
or pos_label=None will result in an exception. Please set an explicit 
value for `average`, one of (None, 'micro', 'macro', 'weighted', 
'samples'). In cross validation use, for instance, 
scoring="f1_weighted" instead of scoring="f1".

Anda mendapatkan peringatan ini karena Anda menggunakan skor f1, recall, dan presisi tanpa menentukan cara penghitungannya! Pertanyaannya dapat diubah: dari laporan klasifikasi di atas, bagaimana Anda mengeluarkan satu angka global untuk f1-score? Anda bisa:

  1. Ambil rata-rata skor f1 tiap kelas: itulah avg / totalhasil di atas. Ini juga disebut makro rata-rata.
  2. Hitung skor f1 menggunakan jumlah global positif benar / negatif palsu, dll. (Anda menjumlahkan jumlah positif benar / negatif palsu untuk setiap kelas). Rata- rata alias mikro .
  3. Hitung rata-rata tertimbang dari skor f1. Menggunakan 'weighted'dalam scikit-learn akan menimbang skor f1 dengan dukungan kelas: semakin banyak elemen yang dimiliki kelas, semakin penting skor f1 untuk kelas ini dalam penghitungan.

Ini adalah 3 opsi di scikit-learn, ada peringatan yang mengatakan Anda harus memilih satu . Jadi, Anda harus menentukan averageargumen untuk metode skor.

Yang mana yang Anda pilih tergantung bagaimana Anda ingin mengukur kinerja pengklasifikasi: misalnya, rata-rata makro tidak memperhitungkan ketidakseimbangan kelas dan skor f1 kelas 1 akan sama pentingnya dengan skor kelas f1 5. Namun, jika Anda menggunakan rata-rata tertimbang, Anda akan menjadi lebih penting untuk kelas 5.

Seluruh spesifikasi argumen dalam metrik ini tidak terlalu jelas di scikit-learn sekarang, itu akan menjadi lebih baik di versi 0.18 menurut dokumen. Mereka menghapus beberapa perilaku standar yang tidak jelas dan mereka mengeluarkan peringatan sehingga pengembang menyadarinya.

Menghitung skor

Hal terakhir yang ingin saya sebutkan (jangan ragu untuk melewatinya jika Anda menyadarinya) adalah bahwa skor hanya berarti jika dihitung pada data yang belum pernah dilihat oleh pengklasifikasi . Ini sangat penting karena skor apa pun yang Anda peroleh pada data yang digunakan untuk menyesuaikan pengklasifikasi sama sekali tidak relevan.

Berikut adalah cara untuk melakukannya dengan menggunakan StratifiedShuffleSplit, yang memberi Anda pemisahan data secara acak (setelah pengacakan) yang mempertahankan distribusi label.

from sklearn.datasets import make_classification
from sklearn.cross_validation import StratifiedShuffleSplit
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score, classification_report, confusion_matrix

# We use a utility to generate artificial classification data.
X, y = make_classification(n_samples=100, n_informative=10, n_classes=3)
sss = StratifiedShuffleSplit(y, n_iter=1, test_size=0.5, random_state=0)
for train_idx, test_idx in sss:
    X_train, X_test, y_train, y_test = X[train_idx], X[test_idx], y[train_idx], y[test_idx]
    svc.fit(X_train, y_train)
    y_pred = svc.predict(X_test)
    print(f1_score(y_test, y_pred, average="macro"))
    print(precision_score(y_test, y_pred, average="macro"))
    print(recall_score(y_test, y_pred, average="macro"))    

Semoga ini membantu.

ldirer
sumber
Untuk multikelas, bagaimana Anda menentukan bobot kelas? Misalnya, apa class_weight={1:10}artinya data yang memiliki 3 kelas?
Aziz Javed
Apakah ada cara untuk mendapatkan skor akurasi label bijaksana?
Ankur Sinha
Bisakah Anda menjelaskan bagaimana mikro bekerja lebih jelas. Juga Anda tidak menyebutkan apa pun tentang biner
rendah hati
Bagi saya, pengacakan bertingkat menciptakan masalah, jadi saya beralih kembali ke latihan-tes seperti yang ditunjukkan ValueError: The least populated class in y has only 1 member, which is too few. The minimum number of labels for any class cannot be less than 2.. Ini berfungsi dengan baik dengan train-test split tetapi adakah yang bisa membantu saya mengapa saya menerima kesalahan ini dengan SSS? Terima kasih.
Akash Kandpal
HAI saya menguji kode Anda tetapi saya memiliki pesan kesalahan ini C: \ Users \\ Anaconda3 \ lib \ site-packages \ sklearn \ metrics \ klasifikasi.py: 976: DeprecationWarning: Dari versi 0.18, input biner tidak akan ditangani secara khusus saat menggunakan presisi / penarikan / skor-F rata-rata. Harap gunakan rata-rata = 'biner' untuk melaporkan hanya kinerja kelas yang positif. 'kinerja kelas yang positif.', DeprecationWarning)
Chedi Bechikh
73

Banyak jawaban yang sangat rinci di sini tetapi saya rasa Anda tidak menjawab pertanyaan yang tepat. Saat saya memahami pertanyaannya, ada dua masalah:

  1. Bagaimana cara saya menilai masalah multikelas?
  2. Bagaimana cara menangani data yang tidak seimbang?

1.

Anda dapat menggunakan sebagian besar fungsi penilaian di scikit-learn dengan masalah multikelas dan masalah kelas tunggal. Ex.:

from sklearn.metrics import precision_recall_fscore_support as score

predicted = [1,2,3,4,5,1,2,1,1,4,5] 
y_test = [1,2,3,4,5,1,2,1,1,4,1]

precision, recall, fscore, support = score(y_test, predicted)

print('precision: {}'.format(precision))
print('recall: {}'.format(recall))
print('fscore: {}'.format(fscore))
print('support: {}'.format(support))

Dengan cara ini Anda akan mendapatkan angka yang nyata dan dapat ditafsirkan untuk masing-masing kelas.

| Label | Precision | Recall | FScore | Support |
|-------|-----------|--------|--------|---------|
| 1     | 94%       | 83%    | 0.88   | 204     |
| 2     | 71%       | 50%    | 0.54   | 127     |
| ...   | ...       | ...    | ...    | ...     |
| 4     | 80%       | 98%    | 0.89   | 838     |
| 5     | 93%       | 81%    | 0.91   | 1190    |

Kemudian...

2.

... Anda dapat mengetahui apakah data yang tidak seimbang bahkan menjadi masalah. Jika skor untuk kelas yang kurang terwakili (kelas 1 dan 2) lebih rendah daripada kelas dengan sampel pelatihan lebih banyak (kelas 4 dan 5) maka Anda tahu bahwa data yang tidak seimbang sebenarnya merupakan masalah, dan Anda dapat bertindak sesuai dengan itu, seperti dijelaskan dalam beberapa jawaban lain di utas ini. Namun, jika distribusi kelas yang sama ada dalam data yang ingin Anda prediksi, data pelatihan Anda yang tidak seimbang adalah perwakilan yang baik dari data tersebut, dan karenanya, ketidakseimbangan adalah hal yang baik.

wonderkid2
sumber
1
Pos bagus dan kata-kata bagus. Terima kasih
Alvis
1
Hai, hanya pertanyaan lanjutan: bagaimana Anda mencetak label menggunakan precision_recall_fscore_support? Apakah label dicetak berdasarkan pesanan?
BigD
@BigD Ya, lihat scikit-learn.org/stable/modules/generated/… di bagian paling bawah. Tetapkan average=Nonedan tentukan label, lalu Anda mendapatkan metrik yang Anda cari, untuk setiap label yang Anda tentukan.
wonderkid2
Apakah ada cara untuk mendapatkan skor akurasi label bijaksana?
Ankur Sinha
@trollster Saya tidak yakin apa yang Anda maksud? Bukankah yang saya tunjukkan dalam jawaban skor akurasi berlabel?
wonderkid2
16

Pertanyaan yang diajukan

Menanggapi pertanyaan 'metrik apa yang harus digunakan untuk klasifikasi kelas jamak dengan data tidak seimbang': Pengukuran makro-F1. Macro Precision dan Macro Recall juga dapat digunakan, tetapi tidak mudah diinterpretasikan seperti untuk klasifikasi biner, keduanya sudah dimasukkan ke dalam F-measure, dan kelebihan metrik mempersulit perbandingan metode, penyetelan parameter, dan sebagainya.

Micro averaging sensitif terhadap ketidakseimbangan kelas: jika metode Anda, misalnya, berfungsi baik untuk label yang paling umum dan benar-benar mengacaukan label lain, metrik micro-rata-rata menunjukkan hasil yang baik.

Pembobotan rata-rata tidak cocok untuk data yang tidak seimbang, karena menimbang menurut jumlah label. Selain itu, ini terlalu sulit untuk ditafsirkan dan tidak populer: misalnya, tidak disebutkan rata-rata seperti itu dalam survei yang sangat rinci berikut, saya sangat menyarankan untuk melihat-lihat:

Sokolova, Marina, dan Guy Lapalme. "Analisis sistematis ukuran kinerja untuk tugas klasifikasi." Pemrosesan & Manajemen Informasi 45.4 (2009): 427-437.

Pertanyaan khusus aplikasi

Namun, kembali ke tugas Anda, saya akan meneliti 2 topik:

  1. metrik yang biasa digunakan untuk tugas spesifik Anda - memungkinkan (a) membandingkan metode Anda dengan orang lain dan memahami jika Anda melakukan sesuatu yang salah, dan (b) untuk tidak mengeksplorasinya sendiri dan menggunakan kembali temuan orang lain;
  2. biaya kesalahan yang berbeda dari metode Anda - misalnya, kasus penggunaan aplikasi Anda mungkin hanya mengandalkan ulasan bintang 4 dan 5 - dalam hal ini, metrik yang baik seharusnya hanya menghitung 2 label ini.

Metrik yang umum digunakan. Seperti yang dapat saya simpulkan setelah melihat literatur, ada 2 metrik evaluasi utama:

  1. Ketepatan , yang digunakan, misalnya dalam

Yu, April, dan Daryl Chang. "Prediksi Sentimen Multikelas menggunakan Yelp Business."

( tautan ) - perhatikan bahwa penulis bekerja dengan distribusi peringkat yang hampir sama, lihat Gambar 5.

Pang, Bo, dan Lillian Lee. "Melihat bintang: Memanfaatkan hubungan kelas untuk kategorisasi sentimen sehubungan dengan skala peringkat." Prosiding Pertemuan Tahunan ke-43 tentang Asosiasi Linguistik Komputasi. Association for Computational Linguistics, 2005.

( tautan )

  1. MSE (atau, lebih jarang, Mean Absolute Error - MAE ) - lihat, misalnya,

Lee, Moontae, dan R. Grafe. "Analisis sentimen multikelas dengan ulasan restoran." Proyek Akhir dari CS N 224 (2010).

( tautan ) - mereka mengeksplorasi akurasi dan MSE, menganggap yang terakhir lebih baik

Pappas, Nikolaos, Rue Marconi, dan Andrei Popescu-Belis. "Explaining the Stars: Weighted Multiple-Instance Learning untuk Analisis Sentimen Berbasis Aspek." Prosiding Konferensi 2014 tentang Metode Empiris Dalam Pengolahan Bahasa Alami. No. EPFL-CONF-200899. 2014.

( link ) - mereka menggunakan scikit-learn untuk evaluasi dan pendekatan baseline dan menyatakan bahwa kode mereka tersedia; namun, saya tidak dapat menemukannya, jadi jika Anda membutuhkannya, tulis surat kepada penulis, pekerjaan ini cukup baru dan sepertinya ditulis dengan Python.

Biaya kesalahan yang berbeda . Jika Anda lebih peduli untuk menghindari kesalahan besar, misalnya menilai ulasan 1 bintang hingga 5 bintang atau semacamnya, lihat MSE; jika perbedaan itu penting, tetapi tidak terlalu banyak, coba MAE, karena tidak mengkuadratkan diff; jika tidak tetap dengan Akurasi.

Tentang pendekatan, bukan metrik

Coba pendekatan regresi, misalnya SVR , karena umumnya mengungguli pengklasifikasi Multikelas seperti SVC atau OVA SVM.

Nikita Astrakhantsev
sumber
13

Pertama-tama, sedikit lebih sulit menggunakan analisis penghitungan untuk mengetahui apakah data Anda tidak seimbang atau tidak. Misal: 1 dari 1000 observasi positif hanyalah noise, error atau terobosan dalam ilmu? Kau tak pernah tahu.
Jadi selalu lebih baik untuk menggunakan semua pengetahuan yang tersedia dan memilih statusnya dengan bijak.

Oke, bagaimana jika benar-benar tidak seimbang?
Sekali lagi - lihat data Anda. Terkadang Anda dapat menemukan satu atau dua observasi dikalikan ratusan kali. Terkadang berguna untuk membuat observasi satu kelas palsu ini.
Jika semua data bersih, langkah selanjutnya adalah menggunakan bobot kelas dalam model prediksi.

Jadi bagaimana dengan metrik multikelas?
Menurut pengalaman saya, tidak ada metrik Anda yang biasanya digunakan. Ada dua alasan utama.
Pertama: bekerja dengan probabilitas selalu lebih baik daripada dengan prediksi yang solid (karena bagaimana lagi Anda bisa memisahkan model dengan prediksi 0,9 dan 0,6 jika keduanya memberikan kelas yang sama?)
Dan kedua: jauh lebih mudah untuk membandingkan model prediksi Anda dan membuat model baru yang hanya bergantung pada satu metrik yang baik.
Dari pengalaman saya, saya dapat merekomendasikan logloss atau MSE (atau hanya berarti kesalahan kuadrat).

Bagaimana cara memperbaiki peringatan sklearn?
Cukup (seperti yang diperhatikan yangjie) timpa averageparameter dengan salah satu nilai berikut: 'micro'(hitung metrik secara global), 'macro'(hitung metrik untuk setiap label) atau 'weighted'(sama seperti makro tetapi dengan bobot otomatis).

f1_score(y_test, prediction, average='weighted')

Semua Peringatan Anda muncul setelah memanggil fungsi metrik dengan averagenilai default 'binary'yang tidak sesuai untuk prediksi multikelas.
Semoga beruntung dan bersenang-senanglah dengan pembelajaran mesin!

Edit:
Saya menemukan rekomendasi penjawab lain untuk beralih ke pendekatan regresi (misalnya SVR) yang tidak saya setujui. Sejauh yang saya ingat, tidak ada yang namanya regresi multikelas. Ya, ada regresi multilabel yang jauh berbeda dan ya itu mungkin dalam beberapa kasus beralih antara regresi dan klasifikasi (jika kelas entah bagaimana diurutkan) tetapi cukup jarang.

Apa yang akan saya rekomendasikan (dalam lingkup scikit-learn) adalah mencoba alat klasifikasi lain yang sangat kuat: peningkatan gradien , hutan acak (favorit saya), KNeighbours dan banyak lagi.

Setelah itu Anda dapat menghitung rata-rata aritmatika atau geometri antara prediksi dan sebagian besar waktu Anda akan mendapatkan hasil yang lebih baik.

final_prediction = (KNNprediction * RFprediction) ** 0.5
Vlad Mironov
sumber
1
> "beralih antara regresi dan klasifikasi (jika kelas entah bagaimana diurutkan) tetapi cukup jarang" Ini kasusnya: 5> 4> 3> 2> 1. Saya menyarankan Anda untuk melihat makalah untuk tugas ini - ada banyak pendekatan regresi dan klasifikasi untuk tugas (terkadang dalam pekerjaan yang sama).
Nikita Astrakhantsev
Maka itu bahkan bukan klasifikasi multikelas tetapi regresi sederhana.
Vlad Mironov
Ya, secara internal, atau dari sudut pandang ML, ini adalah regresi, tetapi pada langkah terakhir kita mengonversi hasil regresi menjadi label, jadi ini adalah klasifikasi multikelas - dari sudut pandang pengguna, atau aplikasi.
Nikita Astrakhantsev