138 votes

Variables gaussiennes aléatoires

Existe-t-il une classe dans la bibliothèque standard de .NET qui me donne la possibilité de créer des variables aléatoires qui suivent la distribution gaussienne ?

0 votes

http://mathworld.wolfram.com/Box-MullerTransformation.html En utilisant deux variables aléatoires, vous pouvez générer des valeurs aléatoires selon une distribution gaussienne. Ce n'est pas du tout une tâche difficile.

1 votes

Je voudrais juste ajouter un résultat mathématique qui n'est pas immédiatement utile pour les distributions normales (en raison de la CDF complexe), mais qui est utile pour de nombreuses autres distributions. Si vous placez des nombres aléatoires uniformément distribués dans [0,1] (avec Random.NextDouble() ) dans l'inverse de la CDF de N'IMPORTE QUELLE distribution, vous obtiendrez des nombres aléatoires qui suivent CETTE distribution. Si votre application n'a pas besoin de variables précisément distribuées normalement, alors la distribution logistique est une approximation très proche de la normale et possède une CDF facilement inversible.

1 votes

Le site Paquet NuGet MedallionRandom contient une méthode d'extension permettant de récupérer les valeurs normalement distribuées d'une Random en utilisant la transformation de Box-Muller (mentionnée dans plusieurs réponses ci-dessous).

202voto

yoyoyoyosef Points 2311

La suggestion de Jarrett d'utiliser une transformation de Box-Muller est bonne pour une solution rapide et simple. Une mise en œuvre simple :

Random rand = new Random(); //reuse this if you are generating many
double u1 = 1.0-rand.NextDouble(); //uniform(0,1] random doubles
double 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)

4 votes

Je l'ai testé et comparé au RNG Mersenne Twister de MathNet et à la NormalDistribution. Votre version est plus de deux fois plus rapide et le résultat final est fondamentalement le même (inspection visuelle des "cloches").

5 votes

@Johann, si vous cherchez la vitesse pure, alors le Algorithme de Zigorat est généralement reconnue comme l'approche la plus rapide. En outre, l'approche ci-dessus peut être rendue plus rapide en reportant une valeur d'un appel à l'autre.

0 votes

Bonjour, que doit faire le stdDev doit-elle être définie ? Je comprends que cela peut être configuré en fonction de besoins spécifiques, mais existe-t-il des limites (c'est-à-dire des valeurs max/min) ?

68voto

Superbest Points 3464

Cette question semble s'être déplacée en tête de Google pour la génération gaussienne .NET, alors je me suis dit que j'allais poster une réponse.

J'ai fait quelques méthodes d'extension pour la classe .NET Random y compris une implémentation de la transformation de Box-Muller. Puisqu'il s'agit d'extensions, tant que le projet est inclus (ou que vous faites référence à la DLL compilée), vous pouvez toujours effectuer les opérations suivantes

var r = new Random();
var x = r.NextGaussian();

J'espère que personne ne s'offusque de cette publicité éhontée.

Exemple d'histogramme de résultats (une application de démonstration pour le dessiner est incluse) :

enter image description here

1 votes

Votre classe d'extension a quelques éléments que je recherchais ! merci !

1 votes

Vous avez un petit bug dans votre méthode NextGaussian. NextDouble() Renvoie un nombre aléatoire à virgule flottante qui est supérieur ou égal à 0,0 et inférieur à 1,0. Vous devriez donc avoir u1 = 1.0 - NextDouble() .... autre log(0) va exploser

11voto

Jarrett Meyer Points 11147

http://mathworld.wolfram.com/Box-MullerTransformation.html

En utilisant deux variables aléatoires, vous pouvez générer des valeurs aléatoires selon une distribution gaussienne. Ce n'est pas du tout une tâche difficile.

10voto

Drew Noakes Points 69288

J'ai créé une demande pour une telle fonctionnalité sur Microsoft Connect. Si c'est quelque chose que vous recherchez, veuillez voter pour cette demande et augmenter sa visibilité.

https://connect.microsoft.com/VisualStudio/feedback/details/634346/guassian-normal-distribution-random-numbers

Cette fonctionnalité est incluse dans le SDK Java. Son implémentation est disponible [dans le cadre de la documentation](http://download.oracle.com/javase/1.4.2/docs/api/java/util/Random.html#nextGaussian()) et est facilement portable vers C# ou d'autres langages .NET.

Si vous recherchez la vitesse pure, alors le Algorithme de Zigorat est généralement reconnue comme l'approche la plus rapide.

Je ne suis pas un expert en la matière, mais j'en ai eu besoin lors de la mise en œuvre d'un système de gestion de l'information. filtre à particules pour mon Bibliothèque de football robotisé simulé RoboCup 3D et j'ai été surpris que cela ne soit pas inclus dans le cadre.


En attendant, voici un wrapper pour Random qui fournit une mise en œuvre efficace de la méthode polaire de Box Muller :

public sealed class GaussianRandom
{
    private bool _hasDeviate;
    private double _storedDeviate;
    private readonly Random _random;

    public GaussianRandom(Random random = null)
    {
        _random = random ?? new Random();
    }

    /// <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>
    public double NextGaussian(double mu = 0, double sigma = 1)
    {
        if (sigma <= 0)
            throw new ArgumentOutOfRangeException("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 deviate
        var polar = Math.Sqrt(-2*Math.Log(rSquared)/rSquared);
        // store first deviate
        _storedDeviate = v2*polar;
        _hasDeviate = true;
        // return second deviate
        return v1*polar*sigma + mu;
    }
}

0 votes

J'ai cependant obtenu des valeurs négatives. Quelqu'un peut-il vérifier ce qui ne va pas ?

0 votes

@mk7, une fonction de probabilité gaussienne centrée autour de zéro est tout aussi susceptible de donner des valeurs négatives que des valeurs positives.

0 votes

Vous avez raison ! Comme j'aimerais obtenir une liste de poids dans une population typique avec un PDF gaussien, je fixe mu à, disons, 75 [en kg] et sigma à 10. Dois-je créer une nouvelle instance de GaussianRandom pour générer chaque poids aléatoire ?

5voto

Jason DeFontes Points 1702

Math.NET Iridium prétend également mettre en œuvre des "générateurs aléatoires non uniformes (normal, poisson, binomial, ...)".

0 votes

Mais il ne fonctionne pas correctement. J'ai essayé de le tracer, en donnant un numéro aléatoire uniforme.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X