Saya telah membaca tentang trik log-sum-exp di banyak tempat (misalnya di sini , dan di sini ) tetapi belum pernah melihat contoh bagaimana itu diterapkan secara khusus untuk classifier Naive Bayes (misalnya dengan fitur diskrit dan dua kelas)
Bagaimana tepatnya seseorang menghindari masalah underflow numerik menggunakan trik ini?
naive-bayes
underflow
Josh
sumber
sumber
Jawaban:
Dalam
baik penyebut dan pembilangnya bisa menjadi sangat kecil, biasanya karena bisa mendekati 0 dan kami mengalikan banyak dari mereka satu sama lain. Untuk mencegah underflow, seseorang dapat dengan mudah mengambil log dari pembilang, tetapi kita perlu menggunakan trik log-sum-exp untuk penyebut.p(xi|Ck)
Lebih khusus lagi, untuk mencegah underflow:
Jika kita hanya peduli mengetahui kelas mana input kemungkinan besar milik dengan aturan keputusan maksimum a posteriori (MAP), kita tidak harus menerapkan trik log-sum-exp, karena kita tidak harus menghitung penyebut dalam kasus itu. Untuk pembilang, cukup ambil log untuk mencegah arus bawah: . Lebih spesifik:( x = x 1 , ... , x n ) l o g ( p ( x | Y = C ) p ( Y = C ) )(y^) (x=x1,…,xn) log(p(x|Y=C)p(Y=C))
yang menjadi setelah mengambil log:
Jika kita ingin menghitung probabilitas kelas , kita perlu menghitung penyebutnya:p ( Y= C| x )
Elemen dapat di bawah karena bisa sangat kecil: ini adalah masalah yang sama seperti pada pembilang, tetapi kali ini kami memiliki penjumlahan di dalam logaritma, yang mencegah kami mengubah (bisa dekat dengan 0) ke dalam (negatif dan tidak dekat dengan 0 lagi, karena ). Untuk menghindari masalah ini, kita dapat menggunakan fakta bahwa untuk mendapatkan:catatan( ∑ | C|k = 1p ( x | Y= Ck) p ( Y= Ck) ) log i | C k ) p ( x i | C k ) ( p ( x i | C k ) ) 0p ( xsaya| Ck) p ( xsaya| Ck) catatan( p ( xsaya| Ck) ) p ( x i | C k ) = exp ( log ( p ( x i | C k ) )0 ≤ p ( xsaya| Ck) ≤ 1 p ( xsaya| Ck) = exp( log( p ( xsaya| Ck) ) )
Pada titik itu, muncul masalah baru: mungkin cukup negatif, yang menyiratkan bahwa dapat menjadi sangat dekat dengan 0, yaitu underflow. Di sinilah kami menggunakan trik log-sum-exp : exp ( log ( p ( x | Y = C k ) p ( Y = C k ) ) )catatan( p ( x | Y= Ck) p ( Y= Ck) ) exp( log( p ( x | Y= Ck) p ( Y= Ck) ) )
dengan:
Kita dapat melihat bahwa memperkenalkan variabel menghindari arus bawah. Misalnya dengan , kita memiliki:SEBUAH k = 2 , a1= - 245 , a2= - 255
Dengan menggunakan trik log-sum-exp kita menghindari underflow, dengan :A=max(−245,−255)=−245 log∑keak=log∑keakeA−A=A+log∑keak−A=−245+log∑keak+245=−245+log(e−245+245+e−255+245)=−245+log(e0+e−10)
Kami menghindari aliran bawah karena jauh lebih jauh dari 0 daripada atau . 3.96143e−10 1.798486 × 10 - 1113.96143×10−107 1.798486×10−111
sumber
Misalkan kita ingin mengidentifikasi dari dua basis data mana yang lebih mungkin menghasilkan frasa (misalnya, novel mana yang frasa ini lebih cenderung berasal). Kita dapat mengasumsikan independensi kata-kata yang tergantung pada database (asumsi Naif Bayes).
Sekarang lihat tautan kedua yang telah Anda poskan. Di sana akan mewakili probabilitas gabungan dari mengamati kalimat yang diberikan database dan akan mewakili probabilitas mengamati setiap kata dalam kalimat.a ebt
sumber
Kita dapat melihat dari jawaban ini bahwa angka terkecil dalam Python (anggap saja) adalah
5e-324
karena IEEE754 , dan penyebab perangkat keras juga berlaku untuk bahasa lain.Dan setiap float yang lebih kecil dari itu akan menghasilkan 0.
Dan mari kita lihat fungsi Naif Bayes
with discrete features and two classes
seperti yang Anda inginkan:Biarkan saya instantiate fungsi itu dengan tugas NLP sederhana di bawah.
Kami memutuskan untuk mendeteksi apakah email yang datang adalah spam ( ) atau bukan spam ( ) dan kami memiliki kosakata kata berukuran 5.000 ( ) dan satu-satunya masalah adalah jika sebuah kata ( ) muncul ( ) di email atau tidak ( ) untuk kesederhanaan ( Bernoulli naif Bayes ).S=1 S=0 n=5,000 wi p(wi|S=1) 1−p(wi|S=1)
Kita dapat melihat bahwa akan sangat kecil karena probabilitasnya (baik dan akan berada antara 0 dan 1) di , dan karenanya kami yakin bahwa produk akan lebih kecil dari dan kami hanya mendapatkan .p(S=s)∏ni=1p(wi|S=s) p(wi|S=1) 1−p(wi|S=1) ∏5000i 5e−324 0/0
Kemudian muncul masalah: Bagaimana kita bisa menghitung probabilitas email adalah spam ? Atau bagaimana kita bisa menghitung pembilang dan penyebutnya?p(S=1|w1,...wn)
Kita bisa melihat implementasi resmi di sklearn :
Untuk pembilang itu dikonversi produk probabilitas ke jumlah kemungkinan log dan untuk penyebutnya menggunakan logsumexp dalam scipy yaitu:
Karena kita tidak dapat menambahkan dua probabilitas gabungan dengan menambahkan log kemungkinan gabungannya, dan kita harus keluar dari ruang log ke ruang probabilitas. Tetapi kami tidak dapat menambahkan dua probabilitas benar karena terlalu kecil dan kami harus menskalakannya dan melakukan penambahan: dan mengembalikan hasilnya ke dalam ruang log lalu kembali: di ruang log dengan menambahkan .∑s={0,1}ejlls−max_jll log∑s={0,1}ejlls−max_jll max_jll+log∑s={0,1}ejlls−max_jll max_jll
Dan di sini adalah derivasi:
di mana adalah dalam kode.max_jll a_max
Setelah kita mendapatkan pembilang dan penyebut dalam ruang log kita bisa mendapatkan probabilitas bersyarat log ( ) dengan mengurangi penyebut dari pembilang :logp(S=1|w1,...wn)
Semoga itu bisa membantu.
Referensi:
1. Bernoulli Naive Bayes Classifier
2. Penyaringan Spam dengan Naive Bayes - Naive Bayes yang mana?
sumber