vendredi 26 juin 2015

In Powershell, How to generate a random variable (exponential) with a specified mean?

I am trying to write a basic simulation (a queue), which relies on generating random expovariates. While Powershell offers a Get-Random function, you can specify a min and a max, but it doesn't have anywhere near Python's random.expovariate(lambd) function.

Supposedly this is the model I should be following: log(1-$u)/(−λ)

The excellent Python documentation has this to say about it:

"Exponential distribution. lambd is 1.0 divided by the desired mean. It should be nonzero. (The parameter would be called “lambda”, but that is a reserved word in Python.) Returned values range from 0 to positive infinity if lambd is positive, and from negative infinity to 0 if lambd is negative.". In another description, "expovariate() produces an exponential distribution useful for simulating arrival or interval time values for in homogeneous Poisson processes such as the rate of radioactive decay or requests coming into a web server.

The Pareto, or power law, distribution matches many observable phenomena and was popularized by Chris Anderon’s book, The Long Tail. The paretovariate() function is useful for simulating allocation of resources to individuals (wealth to people, demand for musicians, attention to blogs, etc.)."

I have tried writing this in Powershell, but my distributions are way off. If I put in a mean of 3 I am getting the results that closely follow the results I should get from a mean of 1. My code is closely modeled on John D. Cook's SimpleRNG C# library.

function GetUniform #GetUint
{
    Return Get-Random -Minimum -0.00 -Maximum 1
}



# Get exponential random sample with specified mean
function GetExponential_SpecMean{
param([double]$mean)

    if ($mean -le 0.0)
    {
                Write-Host "Mean must be positive. Received $mean."

            }
    $a = GetExponential
    $R = $mean * $a
    Return $R
}


# Get exponential random sample with mean 1
function GetExponential
{
    $x = GetUniform
    Return -[math]::log10(1-$x) # -Math.Log( GetUniform() );
}

cls
$mean5 = 1
$rangeBottom = 3.0
$rangeTop = 4.0

$j = 0
$k = 0
$l = 0

    for($i=1; $i -le 1000; $i++){
        $a = GetExponential_SpecMean $mean5

        if($a -le 1.0){Write-Host $a;$j++}
        if($a -gt 1.0){Write-Host $a;$k++}
        if(($a -gt $rangeBottom) -and ($a -le $rangeTop)){#Write-Host $a;
        $l++}

        Write-Host "                      -> $i "
        }

Write-Host "One or less: $j"
Write-Host "Greater than one: $k"
Write-Host "Total in range between bottom $rangeBottom  and top $rangeTop : $l"

For a sample of 1000 and a Mean ($mean5) of 1, I should get (I believe) 500 results that are 1.0 or less and 500 that are greater than 1.0 (1:1 ratio), however I am getting a ratio of about 9:1 with a mean of 1 and a ratio of about 53:47 using a mean of 3.

There is some discussion in this Stack Overflow question with some good background, but it is not specific to Powershell: Pseudorandom Number Generator - Exponential Distribution




Aucun commentaire:

Enregistrer un commentaire