Saya hanya ingin menambahkan hasil matematika yang tidak langsung berguna untuk distribusi Normal (karena CDF kompleks), tetapi berguna untuk banyak distribusi lainnya. Jika Anda memasukkan bilangan acak terdistribusi seragam di [0,1] (dengan Random.NextDouble()) ke dalam kebalikan dari CDF distribusi APAPUN, Anda akan mendapatkan bilangan acak yang mengikuti distribusi ITU. Jika aplikasi Anda tidak membutuhkan variabel terdistribusi normal secara tepat, Distribusi Logistik adalah perkiraan yang sangat dekat dengan normal dan memiliki CDF yang mudah dibalik.
Ozzah
1
Paket MedallionRandom NuGet berisi metode ekstensi untuk mengambil nilai terdistribusi normal dari Randommenggunakan transformasi Box-Muller (disebutkan dalam beberapa jawaban di bawah).
ChaseMedallion
Jawaban:
182
Saran Jarrett untuk menggunakan transformasi Box-Muller bagus untuk solusi cepat dan kotor. Implementasi sederhana:
Random rand =newRandom();//reuse this if you are generating manydouble u1 =1.0-rand.NextDouble();//uniform(0,1] random doublesdouble u2 =1.0-rand.NextDouble();double randStdNormal =Math.Sqrt(-2.0*Math.Log(u1))*Math.Sin(2.0*Math.PI * u2);//random normal(0,1)double randNormal =
mean + stdDev * randStdNormal;//random normal(mean,stdDev^2)
Saya mengujinya dan dibandingkan dengan Mersenne Twister RNG dan NormalDistribution dari MathNet. Versi Anda lebih dari dua kali lebih cepat dan hasil akhirnya pada dasarnya sama (inspeksi visual dari "lonceng").
Johann Gerell
4
@Johann, jika Anda mencari kecepatan murni, maka Algoritma Zigorat secara umum dikenal sebagai pendekatan tercepat. Selanjutnya pendekatan di atas dapat dibuat lebih cepat dengan membawa nilai dari satu panggilan ke panggilan berikutnya.
Drew Noakes
Hai, stdDevvariabel mana yang harus disetel? Saya memahami bahwa ini dapat dikonfigurasi untuk persyaratan tertentu, tetapi apakah ada batasan (yaitu nilai maks / min)?
hofnarwillie
@hofnarwillie stdDev adalah parameter skala dari distribusi normal, yang dapat berupa bilangan positif apapun. Semakin besar nilainya, semakin banyak pula angka yang dihasilkan. Untuk distribusi normal standar menggunakan parameter mean = 0 dan stdDev = 1.
yoyoyosef
1
@ Saya tidak berpikir begitu. Hanya matematika -2 *. Log (u1) yang berada di dalam akar kuadrat, dan log akan selalu negatif atau nol karena u1 <= 1
yoyoyosef
63
Pertanyaan ini tampaknya telah dipindahkan ke atas Google untuk generasi Gaussian .NET, jadi saya pikir saya akan memposting jawaban.
Saya telah membuat beberapa metode ekstensi untuk kelas .NET Random , termasuk implementasi transformasi Box-Muller. Karena mereka adalah ekstensi, selama proyek disertakan (atau Anda mereferensikan DLL yang dikompilasi), Anda masih dapat melakukannya
var r =newRandom();var x = r.NextGaussian();
Semoga tidak ada yang keberatan dengan steker yang tidak tahu malu.
Contoh histogram hasil (aplikasi demo untuk menggambar ini disertakan):
Kelas ekstensi Anda memiliki beberapa hal yang saya cari! Terima kasih!
Thomas
1
Anda memiliki bug kecil dalam metode NextGaussian Anda. NextDouble () Mengembalikan angka floating-point acak yang lebih besar dari atau sama dengan 0,0, dan kurang dari 1,0. Jadi Anda harus memiliki u1 = 1.0 - NextDouble () .... log lain (0) akan meledak
Mitch Wheat
21
Math.NET menyediakan fungsionalitas ini. Begini caranya:
double mean =100;double stdDev =10;MathNet.Numerics.Distributions.Normal normalDist =newNormal(mean, stdDev);double randomGaussianValue= normalDist.Sample();
Jawaban yang bagus! Fungsi ini tersedia di NuGet dalam paket MathNet.Numerics . Selalu hebat untuk tidak harus menggulung sendiri.
jpmc26
8
Saya membuat permintaan untuk fitur seperti itu di Microsoft Connect. Jika ini adalah sesuatu yang Anda cari, silakan pilih dan tingkatkan visibilitasnya.
Fitur ini termasuk dalam Java SDK. Implementasinya tersedia sebagai bagian dari dokumentasi dan dengan mudah diporting ke C # atau bahasa .NET lainnya.
Jika Anda mencari kecepatan murni, maka Algoritma Zigorat secara umum dikenal sebagai pendekatan tercepat.
Sementara itu, berikut adalah pembungkusnya Randomyang menyediakan implementasi yang efisien dari metode kutub Box Muller:
publicsealedclassGaussianRandom{privatebool _hasDeviate;privatedouble _storedDeviate;privatereadonlyRandom _random;publicGaussianRandom(Random random =null){
_random = random ??newRandom();}/// <summary>/// Obtains normally (Gaussian) distributed random numbers, using the Box-Muller/// transformation. This transformation takes two uniformly distributed deviates/// within the unit circle, and transforms them into two independently/// distributed normal deviates./// </summary>/// <param name="mu">The mean of the distribution. Default is zero.</param>/// <param name="sigma">The standard deviation of the distribution. Default is one.</param>/// <returns></returns>publicdoubleNextGaussian(double mu =0,double sigma =1){if(sigma <=0)thrownewArgumentOutOfRangeException("sigma","Must be greater than zero.");if(_hasDeviate){
_hasDeviate =false;return _storedDeviate*sigma + mu;}double v1, v2, rSquared;do{// two random values between -1.0 and 1.0
v1 =2*_random.NextDouble()-1;
v2 =2*_random.NextDouble()-1;
rSquared = v1*v1 + v2*v2;// ensure within the unit circle}while(rSquared >=1|| rSquared ==0);// calculate polar tranformation for each deviatevar polar =Math.Sqrt(-2*Math.Log(rSquared)/rSquared);// store first deviate
_storedDeviate = v2*polar;
_hasDeviate =true;// return second deviatereturn v1*polar*sigma + mu;}}
Saya mendapat beberapa nilai darinya. bisakah seseorang memeriksa apa yang salah?
mk7
@ mk7, fungsi probabilitas Gaussian yang berpusat di sekitar nol kemungkinan besar memberikan nilai negatif seperti halnya memberikan nilai positif.
Drew Noakes
Kamu benar! Karena saya ingin mendapatkan daftar bobot dalam populasi tipikal dengan gaussian PDF, saya menyetel mu menjadi, katakanlah, 75 [dalam kg] dan sigma menjadi 10. Apakah saya perlu menyetel contoh baru GaussianRandom untuk menghasilkan setiap bobot acak?
mk7
Anda dapat terus menggambar sampel dari satu contoh.
Drew Noakes
5
Math.NET Iridium juga mengklaim menerapkan "generator acak tidak seragam (normal, poisson, binomial, ...)".
Tapi itu tidak berfungsi dengan baik. Mencoba untuk merencanakannya, Memberikan no acak seragam.
Nikhil Chilwant
4
Berikut adalah solusi cepat dan kotor lainnya untuk menghasilkan variabel acak yang terdistribusi normal . Ini menarik beberapa titik acak (x, y) dan memeriksa apakah titik ini terletak di bawah kurva fungsi kepadatan probabilitas Anda, jika tidak ulangi.
staticRandom _rand =newRandom();publicstaticdoubleDraw(){while(true){// Get random values from interval [0,1]var x = _rand.NextDouble();var y = _rand.NextDouble();// Is the point (x,y) under the curve of the density function?if(y < f(x))return x;}}// Normal (or gauss) distribution functionpublicstaticdouble f(double x,doubleμ=0.5,doubleσ=0.5){return1d/Math.Sqrt(2*σ*σ*Math.PI)*Math.Exp(-((x -μ)*(x -μ))/(2*σ*σ));}
Penting: Pilih interval y dan parameter σ dan μ sehingga kurva fungsi tidak terpotong pada titik maksimum / minimumnya (misalnya pada x = mean). Pikirkan interval x dan y sebagai kotak pembatas, di mana kurva harus pas.
Tangenial, tetapi ini sebenarnya pertama kalinya saya menyadari Anda dapat menggunakan simbol Unicode untuk variabel alih-alih sesuatu yang bodoh seperti _sigma atau _phi ...
Slothario
@Slothario Saya berterima kasih kepada developer di mana pun karena telah menggunakan 'sesuatu yang bodoh': |
pengguna2864740
2
Saya ingin memperluas jawaban @ yoyoyosef dengan membuatnya lebih cepat, dan menulis kelas pembungkus. Overhead yang dikeluarkan mungkin tidak berarti dua kali lebih cepat, tapi menurut saya seharusnya hampir dua kali lebih cepat. Ini tidak aman untuk benang.
Memperluas jawaban @Noakes dan @ Hameer, saya juga telah menerapkan kelas 'Gaussian', tetapi untuk menyederhanakan ruang memori, saya menjadikannya anak dari kelas Random sehingga Anda juga dapat memanggil dasar Next (), NextDouble () , dll dari kelas Gaussian juga tanpa harus membuat objek Random tambahan untuk menanganinya. Saya juga menghilangkan properti kelas global _available, dan _nextgauss, karena saya tidak melihatnya seperlunya karena kelas ini berbasis instance, seharusnya aman untuk thread, jika Anda memberikan objek Gaussiannya sendiri pada setiap thread. Saya juga memindahkan semua variabel yang dialokasikan waktu proses keluar dari fungsi dan menjadikannya properti kelas, ini akan mengurangi jumlah panggilan ke manajer memori karena 4 ganda secara teoritis tidak boleh dialokasikan sampai objek dihancurkan.
publicclassGaussian:Random{privatedouble u1;privatedouble u2;privatedouble temp1;privatedouble temp2;publicGaussian(int seed):base(seed){}publicGaussian():base(){}/// <summary>/// Obtains normally (Gaussian) distrubuted random numbers, using the Box-Muller/// transformation. This transformation takes two uniformly distributed deviates/// within the unit circle, and transforms them into two independently distributed normal deviates./// </summary>/// <param name="mu">The mean of the distribution. Default is zero</param>/// <param name="sigma">The standard deviation of the distribution. Default is one.</param>/// <returns></returns>publicdoubleRandomGauss(double mu =0,double sigma =1){if(sigma <=0)thrownewArgumentOutOfRangeException("sigma","Must be greater than zero.");
u1 =base.NextDouble();
u2 =base.NextDouble();
temp1 =Math.Sqrt(-2*Math.Log(u1));
temp2 =2*Math.PI * u2;return mu + sigma*(temp1 *Math.Cos(temp2));}}
Memperluas jawaban Drew Noakes, jika Anda membutuhkan kinerja yang lebih baik daripada Box-Muller (sekitar 50-75% lebih cepat), Colin Green telah membagikan implementasi algoritma Ziggurat di C #, yang dapat Anda temukan di sini:
Ziggurat menggunakan tabel pencarian untuk menangani nilai yang jatuh cukup jauh dari kurva, yang akan dengan cepat menerima atau menolaknya. Sekitar 2,5% dari waktu, itu harus melakukan perhitungan lebih lanjut untuk menentukan sisi kurva mana sebuah angka berada.
Anda dapat mencoba Infer.NET. Ini belum berlisensi komersial. Di sini ada tautan
Ini adalah kerangka kerja probabilistik untuk .NET mengembangkan penelitian Microsoft saya. Mereka memiliki tipe .NET untuk distribusi Bernoulli, Beta, Gamma, Gaussian, Poisson, dan mungkin beberapa lagi yang saya tinggalkan.
Itu mungkin mencapai apa yang Anda inginkan. Terima kasih.
Ini adalah implementasi sederhana yang terinspirasi dari Box Muller. Anda dapat meningkatkan resolusi agar sesuai dengan kebutuhan Anda. Meskipun ini berfungsi dengan baik untuk saya, ini adalah perkiraan rentang terbatas, jadi ingatlah bahwa ekornya tertutup dan terbatas, tetapi tentu saja Anda dapat mengembangkannya sesuai kebutuhan.
Ini adalah implementasi sederhana yang terinspirasi dari Box Muller. Anda dapat meningkatkan resolusi agar sesuai dengan kebutuhan Anda. Ini sangat cepat, sederhana, dan berfungsi untuk aplikasi jaringan neural saya yang memerlukan perkiraan jenis fungsi kepadatan probabilitas jenis Gaussian untuk menyelesaikan pekerjaan. Semoga dapat membantu seseorang menghemat waktu dan siklus CPU. Meskipun ini berfungsi dengan baik untuk saya, ini adalah perkiraan rentang terbatas, jadi ingatlah bahwa ekornya tertutup dan terbatas, tetapi tentu saja Anda dapat mengembangkannya sesuai kebutuhan.
Daniel Howard
1
Hai Daniel, saya telah menyarankan pengeditan yang menggabungkan deskripsi dari komentar Anda ke dalam jawaban itu sendiri. Ini juga menghapus '//' yang mengomentari kode sebenarnya dalam jawaban Anda. Anda dapat mengeditnya sendiri jika Anda ingin / jika ditolak :)
mbrig
-1
Saya rasa tidak ada. Dan saya sangat berharap tidak ada, karena kerangka kerjanya sudah cukup membengkak, tanpa fungsionalitas khusus seperti itu yang mengisinya lebih banyak lagi.
Sejak kapan distribusi Gaussian 'terspesialisasi'? Ini jauh lebih umum daripada, katakanlah, AJAX atau DataTables.
TraumaPony
@TraumaPony: apakah Anda serius mencoba menyarankan lebih banyak pengembang menggunakan distribusi Gaussian daripada menggunakan AJAX secara teratur?
David Arno
3
Mungkin; apa yang saya katakan adalah bahwa itu jauh lebih terspesialisasi. Ini hanya memiliki satu aplikasi web penggunaan. Distribusi Gaussian memiliki banyak sekali kegunaan yang tidak terkait.
TraumaPony
@DavidArno, apakah Anda benar-benar menyarankan agar lebih sedikit fungsionalitas yang meningkatkan kerangka kerja.
Jodrell
1
@ Jodrell, untuk mengutip contoh spesifik, saya pikir keputusan untuk membuat MVC kerangka kerja terpisah, daripada bagian dari kerangka .NET utama, adalah keputusan yang bagus.
Random.NextDouble()
) ke dalam kebalikan dari CDF distribusi APAPUN, Anda akan mendapatkan bilangan acak yang mengikuti distribusi ITU. Jika aplikasi Anda tidak membutuhkan variabel terdistribusi normal secara tepat, Distribusi Logistik adalah perkiraan yang sangat dekat dengan normal dan memiliki CDF yang mudah dibalik.Random
menggunakan transformasi Box-Muller (disebutkan dalam beberapa jawaban di bawah).Jawaban:
Saran Jarrett untuk menggunakan transformasi Box-Muller bagus untuk solusi cepat dan kotor. Implementasi sederhana:
sumber
stdDev
variabel mana yang harus disetel? Saya memahami bahwa ini dapat dikonfigurasi untuk persyaratan tertentu, tetapi apakah ada batasan (yaitu nilai maks / min)?Pertanyaan ini tampaknya telah dipindahkan ke atas Google untuk generasi Gaussian .NET, jadi saya pikir saya akan memposting jawaban.
Saya telah membuat beberapa metode ekstensi untuk kelas .NET Random , termasuk implementasi transformasi Box-Muller. Karena mereka adalah ekstensi, selama proyek disertakan (atau Anda mereferensikan DLL yang dikompilasi), Anda masih dapat melakukannya
Semoga tidak ada yang keberatan dengan steker yang tidak tahu malu.
Contoh histogram hasil (aplikasi demo untuk menggambar ini disertakan):
sumber
Math.NET menyediakan fungsionalitas ini. Begini caranya:
Anda dapat menemukan dokumentasinya di sini: http://numerics.mathdotnet.com/api/MathNet.Numerics.Distributions/Normal.htm
sumber
Saya membuat permintaan untuk fitur seperti itu di Microsoft Connect. Jika ini adalah sesuatu yang Anda cari, silakan pilih dan tingkatkan visibilitasnya.
https://connect.microsoft.com/VisualStudio/feedback/details/634346/guassian-normal-distribution-random-numbers
Fitur ini termasuk dalam Java SDK. Implementasinya tersedia sebagai bagian dari dokumentasi dan dengan mudah diporting ke C # atau bahasa .NET lainnya.
Jika Anda mencari kecepatan murni, maka Algoritma Zigorat secara umum dikenal sebagai pendekatan tercepat.
Saya bukan ahli dalam topik ini - saya menemukan kebutuhan untuk ini saat menerapkan filter partikel untuk pustaka robot sepak bola simulasi RoboCup 3D saya dan terkejut ketika ini tidak termasuk dalam kerangka kerja.
Sementara itu, berikut adalah pembungkusnya
Random
yang menyediakan implementasi yang efisien dari metode kutub Box Muller:sumber
Math.NET Iridium juga mengklaim menerapkan "generator acak tidak seragam (normal, poisson, binomial, ...)".
sumber
Berikut adalah solusi cepat dan kotor lainnya untuk menghasilkan variabel acak yang terdistribusi normal . Ini menarik beberapa titik acak (x, y) dan memeriksa apakah titik ini terletak di bawah kurva fungsi kepadatan probabilitas Anda, jika tidak ulangi.
Bonus: Anda dapat membuat variabel acak untuk distribusi lain (misalnya distribusi eksponensial atau distribusi poisson ) hanya dengan mengganti fungsi kerapatan.
Penting: Pilih interval y dan parameter σ dan μ sehingga kurva fungsi tidak terpotong pada titik maksimum / minimumnya (misalnya pada x = mean). Pikirkan interval x dan y sebagai kotak pembatas, di mana kurva harus pas.
sumber
Saya ingin memperluas jawaban @ yoyoyosef dengan membuatnya lebih cepat, dan menulis kelas pembungkus. Overhead yang dikeluarkan mungkin tidak berarti dua kali lebih cepat, tapi menurut saya seharusnya hampir dua kali lebih cepat. Ini tidak aman untuk benang.
sumber
Memperluas jawaban @Noakes dan @ Hameer, saya juga telah menerapkan kelas 'Gaussian', tetapi untuk menyederhanakan ruang memori, saya menjadikannya anak dari kelas Random sehingga Anda juga dapat memanggil dasar Next (), NextDouble () , dll dari kelas Gaussian juga tanpa harus membuat objek Random tambahan untuk menanganinya. Saya juga menghilangkan properti kelas global _available, dan _nextgauss, karena saya tidak melihatnya seperlunya karena kelas ini berbasis instance, seharusnya aman untuk thread, jika Anda memberikan objek Gaussiannya sendiri pada setiap thread. Saya juga memindahkan semua variabel yang dialokasikan waktu proses keluar dari fungsi dan menjadikannya properti kelas, ini akan mengurangi jumlah panggilan ke manajer memori karena 4 ganda secara teoritis tidak boleh dialokasikan sampai objek dihancurkan.
sumber
Memperluas jawaban Drew Noakes, jika Anda membutuhkan kinerja yang lebih baik daripada Box-Muller (sekitar 50-75% lebih cepat), Colin Green telah membagikan implementasi algoritma Ziggurat di C #, yang dapat Anda temukan di sini:
http://heliosphan.org/zigguratalgorithm/zigguratalgorithm.html
Ziggurat menggunakan tabel pencarian untuk menangani nilai yang jatuh cukup jauh dari kurva, yang akan dengan cepat menerima atau menolaknya. Sekitar 2,5% dari waktu, itu harus melakukan perhitungan lebih lanjut untuk menentukan sisi kurva mana sebuah angka berada.
sumber
Anda dapat mencoba Infer.NET. Ini belum berlisensi komersial. Di sini ada tautan
Ini adalah kerangka kerja probabilistik untuk .NET mengembangkan penelitian Microsoft saya. Mereka memiliki tipe .NET untuk distribusi Bernoulli, Beta, Gamma, Gaussian, Poisson, dan mungkin beberapa lagi yang saya tinggalkan.
Itu mungkin mencapai apa yang Anda inginkan. Terima kasih.
sumber
Ini adalah implementasi sederhana yang terinspirasi dari Box Muller. Anda dapat meningkatkan resolusi agar sesuai dengan kebutuhan Anda. Meskipun ini berfungsi dengan baik untuk saya, ini adalah perkiraan rentang terbatas, jadi ingatlah bahwa ekornya tertutup dan terbatas, tetapi tentu saja Anda dapat mengembangkannya sesuai kebutuhan.
sumber
Saya rasa tidak ada. Dan saya sangat berharap tidak ada, karena kerangka kerjanya sudah cukup membengkak, tanpa fungsionalitas khusus seperti itu yang mengisinya lebih banyak lagi.
Lihatlah http://www.extremeoptimization.com/Statistics/UsersGuide/ContinuousDistributions/NormalDistribution.aspx dan http://www.vbforums.com/showthread.php?t=488959 untuk solusi pihak ketiga .NET.
sumber