Scikit-learn: MSE negatif ketika dikembalikan oleh cross_val_score

Dibuat pada 12 Sep 2013  ·  58Komentar  ·  Sumber: scikit-learn/scikit-learn

Mean Square Error yang dikembalikan oleh sklearn.cross_validation.cross_val_score selalu negatif. Meskipun merupakan keputusan yang dirancang agar keluaran dari fungsi ini dapat digunakan untuk pemaksimalan dengan beberapa hyperparameter, ini sangat membingungkan saat menggunakan cross_val_score secara langsung. Setidaknya saya bertanya pada diri sendiri bagaimana mean dari sebuah persegi bisa menjadi negatif dan berpikir bahwa cross_val_score tidak bekerja dengan benar atau tidak menggunakan metrik yang disediakan. Hanya setelah menggali kode sumber sklearn saya menyadari bahwa tanda itu terbalik.

Perilaku ini disebutkan di make_scorer di scorer.py, namun tidak disebutkan di cross_val_score dan saya pikir seharusnya begitu, karena jika tidak maka akan membuat orang berpikir bahwa cross_val_score tidak berfungsi dengan benar.

API Bug Documentation

Komentar yang paling membantu

mungkin negmse akan menyelesaikan masalah

Semua 58 komentar

Anda mengacu pada

greater_is_better : boolean, default=True

Whether score_func is a score function (default), meaning high is good, 
or a loss function, meaning low is good. In the latter case, the scorer 
object will sign-flip the outcome of the score_func.

di http://scikit-learn.org/stable/modules/generated/sklearn.metrics.make_scorer.html
? (hanya untuk referensi)

Saya setuju bahwa ini bisa lebih jelas di dokumen cross_val_score

Terima kasih telah melaporkan

Memang kami mengabaikan masalah itu saat melakukan refactoring Pencetak gol. Berikut ini sangat kontra-intuitif:

>>> import numpy as np
>>> from sklearn.datasets import load_boston
>>> from sklearn.linear_model import RidgeCV
>>> from sklearn.cross_validation import cross_val_score

>>> boston = load_boston()
>>> np.mean(cross_val_score(RidgeCV(), boston.data, boston.target, scoring='mean_squared_error'))
-154.53681864311497

/ cc @larsmans

BTW Saya tidak setuju bahwa ini masalah dokumentasi. Itu cross_val_score harus mengembalikan nilai dengan tanda yang cocok dengan nama penilaian. Idealnya GridSearchCV(*params).fit(X, y).best_score_ harus konsisten. Kalau tidak, API sangat membingungkan.

Saya juga setuju bahwa perubahan untuk mengembalikan MSE yang sebenarnya tanpa mengaktifkan tanda akan menjadi pilihan yang jauh lebih baik.

Objek pencetak bisa saja menyimpan tanda greater_is_better dan setiap kali pencetak digunakan tanda dapat dibalik jika diperlukan, misalnya dalam GridSearchCV .

Saya setuju bahwa kami memiliki masalah kegunaan di sini, tetapi saya tidak sepenuhnya setuju dengan solusi @ogrisel yang seharusnya kami lakukan

kembalikan nilai dengan tanda yang sesuai dengan nama penilaian

karena itu adalah peretasan yang tidak dapat diandalkan dalam jangka panjang. Bagaimana jika seseorang mendefinisikan pencetak gol kustom dengan nama seperti mse ? Bagaimana jika mereka mengikuti pola penamaan tetapi membungkus pencetak gol dengan dekorator yang mengubah nama?

Objek scorer bisa saja menyimpan flag Greater_is_better dan kapanpun scorer digunakan tanda bisa dibalik jika diperlukan, misalnya di GridSearchCV.

Inilah yang awalnya dilakukan oleh pencetak skor, selama pengembangan antara rilis 0,13 dan 0,14 dan itu membuat definisi mereka jauh lebih sulit. Ini juga membuat kode sulit untuk diikuti karena atribut greater_is_better sepertinya hilang di kode pencetak, hanya untuk muncul kembali di tengah kode pencarian grid. Kelas khusus Scorer diperlukan untuk melakukan sesuatu yang idealnya, fungsi sederhana akan melakukannya.

Saya percaya bahwa jika kita ingin mengoptimalkan skor, maka skor harus _maximized_. Demi kemudahan pengguna, saya pikir kami mungkin memperkenalkan parameter score_is_loss["auto", True, False] yang hanya mengubah _display_ skor dan dapat menggunakan heuristik berdasarkan nama bawaan.

Itu adalah respon yang terburu-buru karena saya harus turun dari kereta. Apa yang saya maksud dengan "tampilan" sebenarnya adalah nilai pengembalian dari cross_val_score . Saya pikir pencetak gol harus sederhana dan seragam dan algoritme harus selalu maksimal.

Ini memang memperkenalkan asimetri antara pencetak gol bawaan dan khusus.

Ping @GaelVaroaux.

Saya suka solusi score_is_loss, atau sesuatu seperti itu .. perubahan tanda agar sesuai dengan nama penilaian tampaknya sulit dipertahankan dapat menyebabkan masalah seperti yang disebutkan @larsmans

apa kesimpulannya, solusi mana yang harus kita ambil? :)

@tdomhan @jaquesgrobler @larsmans Tahukah Anda jika ini juga berlaku untuk r2 ? Saya memperhatikan bahwa skor r2 dikembalikan oleh GridSearchCV juga sebagian besar negatif untuk ElasticNet , Lasso dan Ridge .

R² dapat berupa positif atau negatif, dan negatif berarti model Anda berkinerja sangat buruk.

IIRC, @GaelVaroquaux adalah pendukung mengembalikan angka negatif ketika greater_is_better=False .

r2 adalah fungsi skor (lebih besar lebih baik), jadi itu seharusnya positif jika model Anda bagus - tapi itu salah satu dari sedikit metrik kinerja yang sebenarnya bisa negatif, artinya lebih buruk dari 0.

Apa konsensus tentang masalah ini? Menurut pendapat saya, cross_val_score adalah alat evaluasi, bukan pemilihan model. Dengan demikian harus mengembalikan nilai aslinya.

Saya dapat memperbaikinya di PR # 2759 saya, karena perubahan yang saya buat membuatnya sangat mudah untuk diperbaiki. Triknya adalah dengan tidak membalik tanda dimuka tetapi, sebagai gantinya, mengakses atribut greater_is_better pada pencetak gol saat melakukan pencarian kisi.

Apa konsensus tentang masalah ini? Menurut saya, cross_val_score adalah
alat evaluasi, bukan pemilihan model. Dengan demikian seharusnya kembali
nilai aslinya.

Kasus khusus adalah berbagai perilaku yang menjadi sumber masalah dalam perangkat lunak.

Saya hanya berpikir bahwa kita harus mengganti nama "mse" menjadi "negated_mse" dalam daftar
dari string penilaian yang dapat diterima.

Bagaimana jika seseorang menentukan pencetak gol ubahsuaian dengan nama seperti mse? Bagaimana jika mereka mengikuti pola penamaan tetapi membungkus pencetak gol dengan dekorator yang mengubah nama?

Menurut saya @ogrisel tidak menyarankan untuk menggunakan pencocokan nama, hanya agar konsisten dengan metrik aslinya. Koreksi saya jika saya salah @ogrisel.

Saya hanya berpikir bahwa kita harus mengganti nama "mse" menjadi "negated_mse" dalam daftar string penilaian yang dapat diterima.

Itu benar-benar tidak intuitif jika Anda tidak tahu internal scikit-learn. Jika Anda harus membengkokkan sistem seperti itu, saya pikir itu pertanda ada masalah desain.

Itu benar-benar tidak intuitif jika Anda tidak tahu internal scikit-learn.
Jika Anda harus membengkokkan sistem seperti itu, saya pikir itu pertanda ada
masalah desain.

Saya tidak setuju. Manusia memahami hal-hal dengan banyak pengetahuan sebelumnya dan
konteks. Semuanya sistematis. Mencoba menyematkan ini di perangkat lunak
memberikan daftar belanja seperti serangkaian kasus khusus. Tidak hanya membuatnya
perangkat lunak sulit untuk dipelihara, tetapi juga berarti orang yang tidak memilikinya
dalam pikiran pengecualian tersebut mengalami perilaku mengejutkan dan menulis buggy
kode menggunakan perpustakaan.

Kasus khusus apa yang Anda pikirkan?

Untuk lebih jelasnya, menurut saya skor validasi silang yang disimpan dalam objek GridSearchCV harus _also_ menjadi nilai asli (bukan dengan tanda dibalik).

AFAIK, membalik tanda diperkenalkan untuk membuat implementasi pencarian grid sedikit lebih sederhana tetapi tidak seharusnya mempengaruhi kegunaan.

Kasus khusus apa yang Anda pikirkan?

Nah, fakta bahwa untuk beberapa metrik lebih besar lebih baik, sedangkan untuk yang lain
justru sebaliknya.

AFAIK, membalik tanda diperkenalkan untuk membuat pencarian grid
implementasi sedikit lebih sederhana tetapi tidak seharusnya memengaruhi
kegunaan.

Ini bukan tentang pencarian grid, ini tentang pemisahan perhatian: skor
harus dapat digunakan tanpa mengetahui apa pun tentang mereka, atau kode untuk
menangani kekhususan mereka akan menyebar ke seluruh basis kode. Ada
sudah banyak kode scoring.

Tapi itu agak menunda masalah untuk kode pengguna. Tidak ada yang ingin memplot "MSE yang dinegasikan" sehingga pengguna harus membalik kembali tanda di kode mereka. Ini tidak nyaman, terutama untuk laporan validasi silang multi-metrik (PR # 2759), karena Anda perlu menangani setiap metrik satu per satu. Saya ingin tahu apakah kita bisa mendapatkan yang terbaik dari kedua dunia: kode umum dan hasil yang intuitif.

Tapi itu agak menunda masalah untuk kode pengguna. Tidak ada yang mau
untuk memplot "MSE yang dinegasikan" sehingga pengguna harus membalik rambu mereka kembali
kode.

Jelas bukan akhir dunia. Perhatikan bahwa saat membaca makalah atau
melihat presentasi Saya memiliki masalah yang sama: ketika grafik tidak
bagus, saya kehilangan sedikit waktu dan bandwidth mental untuk mencoba
gambar jika lebih besar lebih baik atau tidak.

Ini tidak nyaman, terutama untuk validasi silang multi-metrik
laporan (PR # 2759), karena Anda perlu menangani setiap metrik secara individual.

Mengapa. Jika Anda hanya menerima bahwa selalu lebih besar lebih baik, itu membuatnya
semuanya lebih mudah, termasuk interpretasi hasil.

Saya ingin tahu apakah kita dapat memiliki yang terbaik dari kedua dunia: kode generik dan
hasil intuitif.

Risikonya adalah memiliki kode yang sangat kompleks yang memperlambat kita untuk pemeliharaan
dan pengembangan. Scikit-learn adalah menambah berat badan.

Jika Anda hanya menerima bahwa selalu lebih besar lebih baik

Itu yang dia katakan :)

Lebih serius lagi, saya pikir salah satu alasan ini membingungkan orang adalah karena output cross_val_score tidak konsisten dengan metrik. Jika kami mengikuti logika Anda, semua metrik di sklearn.metrics harus mengikuti "lebih besar lebih baik".

Itu yang dia katakan :)

Bagus!

Lebih serius lagi, saya pikir salah satu alasan mengapa hal ini membingungkan orang adalah karena
output cross_val_score tidak konsisten dengan metrik. Jika kita
ikuti logika Anda, semua metrik di sklearn.metrics harus mengikuti "lebih besar
lebih baik".

Sepakat. Itulah mengapa saya menyukai ide untuk mengubah nama: itu akan muncul
di mata orang-orang.

Lebih serius lagi, menurut saya salah satu alasan mengapa hal ini membingungkan orang adalah karena keluaran dari cross_val_score tidak konsisten dengan metrik.

Dan ini pada gilirannya membuat scoring tampak lebih misterius daripada yang sebenarnya.

Digigit hari ini di 0.16.1 ketika mencoba melakukan regresi linier. Meskipun tanda skor tampaknya tidak dibalik lagi untuk pengklasifikasi, tanda skor tersebut masih dibalik untuk regresi linier. Untuk menambah kebingungan, LinearRegression.score () mengembalikan versi skor yang tidak dibalik.

Saya menyarankan untuk membuat semuanya konsisten dan mengembalikan skor non-sign-flipped untuk model linier juga.

Contoh:

from sklearn import linear_model
from sklearn.naive_bayes import GaussianNB
from sklearn import cross_validation
from sklearn import datasets
iris = datasets.load_iris()
nb = GaussianNB()
scores = cross_validation.cross_val_score(nb, iris.data, iris.target)
print("NB score:\t  %0.3f" % scores.mean() )

iris_reg_data = iris.data[:,:3]
iris_reg_target = iris.data[:,3]
lr = linear_model.LinearRegression()
scores = cross_validation.cross_val_score(lr, iris_reg_data, iris_reg_target)
print("LR score:\t %0.3f" % scores.mean() )

lrf = lr.fit(iris_reg_data, iris_reg_target)
score = lrf.score(iris_reg_data, iris_reg_target)
print("LR.score():\t  %0.3f" % score )

Ini memberi:

NB score:     0.934    # sign is not flipped
LR score:    -0.755    # sign is flipped
LR.score():   0.938    # sign is not flipped

Validasi silang membalik semua tanda model di mana lebih besar lebih baik. Saya masih tidak setuju dengan keputusan ini. Saya pikir pendukung utamanya adalah @GaelVaroquaux dan mungkin @mblondel [Saya ingat Anda melakukan refactoring kode pencetak gol].

Oh sudahlah, semua pembahasan diatas.
Saya merasa membalik tanda secara default di mse dan r2 bahkan kurang intuitif: - /

@Huitzilo GaussianNB adalah pengklasifikasi dan menggunakan akurasi sebagai pencetak gol default. LinearRegression adalah regressor dan menggunakan skor r2 sebagai skor default. Skor kedua negatif tetapi ingat bahwa skor r2 _bisa_ negatif. Selain itu, iris adalah kumpulan data multikelas. Oleh karena itu, targetnya kategoris. Anda tidak dapat menggunakan regressor.

benar, saya agak bingung apa yang terjadi, r2 tidak dibalik ... hanya mse saja.

Mungkin solusi untuk semua masalah ini adalah mengganti nama benda negmse ?

@mblondel tentu anda benar, maaf. Saya baru saja dengan cepat menampar contoh untuk regresi, dan karena terlalu percaya diri pada data iris, saya pikir fitur prediksi # 4 dari yang lain akan berfungsi (dengan R2 positif). Tapi ternyata tidak, karenanya, negatif R2. Tidak ada tanda membalik di sini. BAIK. Salahku.

Namun, tandanya dibalik di MSE yang saya dapatkan dari cross_val_score .

Mungkin hanya saya, tetapi saya menemukan ketidakkonsistenan ini sangat membingungkan (itulah yang membuat saya terlibat dalam masalah ini). Mengapa MSE harus di-sign-flipped, tetapi tidak R2?

Mungkin hanya saya, tetapi saya menemukan ketidakkonsistenan ini sangat membingungkan (itulah yang membuat saya terlibat dalam masalah ini). Mengapa MSE harus di-sign-flipped, tetapi tidak R2?

Karena semantik skor lebih tinggi lebih baik. MSE tinggi itu buruk.

mungkin negmse akan menyelesaikan masalah

@amueller Saya setuju, membuat tanda membalik eksplisit di nama parameter penilaian pasti akan membantu menghindari kebingungan.

Mungkin dokumentasi di [1] juga bisa lebih eksplisit tentang bagaimana tanda membalik beberapa skor. Dalam kasus saya, saya membutuhkan informasi dengan cepat dan hanya melihat tabel di bawah 3.1.1.1, tetapi tidak membaca teksnya (yang menjelaskan prinsip "lebih besar lebih baik"). IMHO, menambahkan komentar untuk mse, median dan mean absolute error pada tabel di bawah 3.1.1.1, yang menunjukkan negasi mereka, akan sangat membantu, tanpa ada perubahan pada kode sebenarnya.

[1] http://scikit-learn.org/stable/modules/model_evaluation.html#scoring -parameter

Saya menemukan kasus yang sangat menarik:

from sklearn.cross_validation import cross_val_score
model = LinearRegression()
scores = cross_val_score(model, X, target, cv=2, scoring='r2')
scores

Hasil dalam

array([-0.17026282, -2.21315179])

Untuk dataset yang sama kode berikut

model = LinearRegression()
model.fit(X, target)
prediction = model.predict(X)
print r2_score(target, prediction)

menghasilkan nilai yang wajar

0.353035789318

AFAIK untuk model regresi linier (dengan intersep) tidak dapat diperoleh R ^ 2> 1 atau R ^ 2 <0

Jadi, hasil cv tidak terlihat seperti R ^ 2 dengan tanda terbalik. Apakah saya salah di beberapa titik?

r2 bisa negatif (untuk model yang buruk). Tidak boleh lebih dari 1.

Anda mungkin overfitting. mencoba:

from sklearn.cross_validation import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, target, test_size=0.2, random_state=0)
model = LinearRegression()
model.fit(X_train, y_train)
pred_train = model.predict(X_train)
print("train r2: %f" % r2_score(y_train, pred_train))

pred_test = model.predict(X_test)
print("test r2: %f" % r2_score(y_test, pred_test))

Coba dengan nilai berbeda untuk seed integer random_state yang mengontrol pemisahan acak.

mungkin negmse akan menyelesaikan masalah

+1 untuk 'neg_mse' (Saya pikir garis bawah membuat hal-hal lebih mudah dibaca).

Apakah itu menyelesaikan semua masalah? Apakah ada skor lain yang lebih besar tidak lebih baik?

Ada:

  • log_loss
  • mean_absolute_error
  • median_absolute_error

Menurut doc/modules/model_evaluation.rst , itu seharusnya semuanya.

Dan hinge_loss kurasa?

Menambahkan awalan neg_ ke semua kerugian itu terasa canggung.

Gagasannya adalah mengembalikan skor asli (tanpa flip tanda) tetapi alih-alih mengembalikan ndarray, kami mengembalikan kelas yang memperluas ndarray dengan metode seperti best() , arg_best() , best_sorted() . Dengan cara ini, hasilnya tidak mengejutkan dan kami memiliki metode praktis untuk mendapatkan hasil terbaik.

Tidak ada pencetak gol untuk kerugian engsel (dan saya tidak pernah melihatnya digunakan untuk evaluasi).

Pencetak gol tidak mengembalikan larik numpy, ia mengembalikan pelampung, bukan?
kita bisa mengembalikan objek skor yang memiliki kustom ">" tetapi terlihat seperti float.
Itu terasa lebih dibuat-buat bagi saya daripada solusi sebelumnya, yang menandai pencetak gol dengan bool "lower_is_better" yang kemudian digunakan di GridSearchCV.

cross_val_score mengembalikan sebuah array.

Sebenarnya skor yang dikembalikan oleh cross_val_score biasanya tidak perlu diurutkan, cukup dirata-ratakan.

Ide lainnya adalah menambahkan metode sorted ke _BaseScorer .

my_scorer = make_scorer(my_metric, greater_is_better=False)
scores = my_scorer.sorted(scores)  # takes into account my_scorer._sign
best = scores[0]

cross_val_score mengembalikan larik, tetapi pencetak gol mengembalikan larik. Saya merasa akan aneh untuk memiliki logika tertentu di cross_val_score karena Anda ingin memiliki perilaku yang sama di GridSearchCV dan di semua objek CV lainnya.

Anda juga memerlukan metode argsort, karena di GridSearchCV Anda menginginkan skor terbaik dan indeks terbaik.

Bagaimana cara mengimplementasikan "perkirakan mean dan varians dari kesalahan pekerja dari pertanyaan kontrol, kemudian menghitung rata-rata tertimbang setelah menghilangkan perkiraan bias untuk prediksi" dengan scikit-learn?

IIRC kami membahas ini di sprint (musim panas lalu ?!) dan memutuskan untuk menggunakan neg_mse (atau apakah itu neg-mse ) dan mencela semua pencetak skor / string di mana kami memiliki tanda negatif sekarang.
Apakah ini masih konsensus? Kita harus melakukannya sebelum 0,18.
Ping @GaelVaroquaux @agramfort @jnothman @ogrisel @raghavrv

ya kami menyetujui neg_mse AFAIK

Itu neg_mse

Kami juga butuh:

  • neg_log_loss
  • neg_mean_absolute_error
  • neg_median_absolute_error

model = Sequential ()
keras.layers.Flatten ()
model.add (Padat (11, input_dim = 3, kernel_initializer = keras.initializers.he_normal (seed = 2),
kernel_regularizer = regularizers.l2 (2)))
keras.layers.LeakyReLU (alpha = 0,1)
model.add (Padat (8, kernel_initializer = keras.initializers.he_normal (seed = 2)))
keras.layers.LeakyReLU (alpha = 0,1)
model.add (Padat (4, kernel_initializer = keras.initializers.he_normal (seed = 2)))
keras.layers.LeakyReLU (alpha = 0,1)
model.add (Padat (1, kernel_initializer = keras.initializers.he_normal (seed = 2)))
keras.layers.LeakyReLU (alpha = 0,2)
adag = RMSprop (lr = 0,0002)
model.compile (kerugian = kerugian.mean_squared_error,
pengoptimal = adag
)
history = model.fit (X_train, Y_train, epochs = 2000,
batch_size = 20, shuffle = True)

Bagaimana cara memvalidasi silang kode di atas? Saya ingin meninggalkan metode validasi silang untuk digunakan dalam hal ini.

@shreyassks ini bukan tempat yang tepat untuk pertanyaan Anda, tetapi saya akan memeriksanya: https://keras.io/scikit-learn-api . Bungkus jaringan Anda dengan scikit-learn estimator lalu gunakan w / model_selection.cross_val_score

Iya. Saya sangat setuju! Ini juga terjadi pada Brier_score_loss, ini bekerja dengan baik menggunakan Brier_score_loss, tetapi membingungkan ketika berasal dari GridSearchCV, Brier_score_loss negatif kembali. Setidaknya, akan lebih baik keluaran seperti, karena Brier_score_loss adalah kerugian (semakin rendah semakin baik), fungsi penilaian di sini membalik tanda untuk menjadikannya negatif.

Idenya adalah bahwa cross_val_score harus sepenuhnya fokus pada nilai absolut dari hasil. Sepengetahuan saya, pentingnya tanda negatif (-) yang diperoleh untuk MSE (mean squared error) di cross_val_score tidak ditentukan sebelumnya. Mari kita tunggu versi terbaru dari sklearn dimana masalah ini ditangani.

Untuk kasus penggunaan Regresi:
model_score = cross_val_score (model, df_input, df_target, scoring = 'neg_mean_squared_error', cv = 3)
Saya mendapatkan nilai sebagai:

SVR:
[-6.20938025 -1.397376 -1.94519]
-3.183982080147279

Regresi linier:
[-5.94898085 -9.30931808 -1.15760676]
-5.4719685646934275

Laso:
[-7.22363814 -10.47734135 -2.20807684]
-6.6363521107522345

Punggung bukit:
[-5.95990385 -4.17946756 -1.36885809]
-3.8360764993832004

Jadi mana yang terbaik?
SVR?

Untuk kasus penggunaan Regresi:
Saya mendapatkan hasil yang berbeda saat saya menggunakan
(1) "cross_val_score" dengan scoring = 'neg_mean_squared_error'
dan
(2) Untuk input yang sama ketika saya menggunakan "GridSearchCV" dan memeriksa 'best_score_'

Untuk model Regresi mana yang lebih baik?

  • "cross_val_score" dengan scoring = 'neg_mean_squared_error'
    (ATAU)
  • gunakan "GridSearchCV" dan periksa 'best_score_'

@priyono_
Anda menanyakan pertanyaan penggunaan. Pelacak masalah terutama untuk bug dan fitur baru. Untuk pertanyaan penggunaan, disarankan untuk mencoba Stack Overflow atau Milis .

Apakah halaman ini membantu?
0 / 5 - 0 peringkat