'What are the arguments for scipy.stats.uniform?

I'm trying to create a uniform distribution between two numbers (lower bound and upper bound) in order to feed it to sklearn's ParameterSampler. I am using scipy.stats.uniform in the following format:

from scipy.stats import uniform    
params = ParameterSampler({'bandwidth':uniform(5,50)}, 20)

But when I get the random selections of the 'bandwidth' parameter, they are not all between 5 and 50. Some of them are bigger than 50 by a bit. So my question is what do the arguments in scipy.stats.uniform represent? Are they not a lower bound and upper bound? The documentation shows no arguments so I can't figure it out from that.



Solution 1:[1]

The first argument is the lower bound, and the second argument is the range of the distribution. So the example distribution in your question is uniform between 5 and 55.

Quoting from the documentation linked in your question:

A uniform continuous random variable.

This distribution is constant between loc and loc + scale.

loc is the first argument and scale is the second argument.

Solution 2:[2]

In the given case the call should look like that:

uniform.rvs(loc=5, scale=45)

Even though it's possible to call the distribution directly with parameters, scipy.stats has the following logic:

<dist_name>.rvs(loc=<param1>, scale=<param2>, size=(Nx, Ny))

Solution 3:[3]

The loc is the lower bound and scale is upper bound subtracted from the lower bound.

Function

Here is a function to do that for you:

from scipy.stats import uniform

def get_uniform(min, max):
    """Transform min (lower bound) and max (upper bound) 
    to scipy.stats.uniform parameters"""
    return uniform(loc=min, scale=max-min)

Proof

I tested it with this:

size = 100000

experiments = [
    (5_000, 10_000),
    (-10_000, -5_000),
    (-1_000, 0),
    (0, 1_000),
]

for lb, ub in experiments:
    print(f"Experiment (Lower: {lb}, Upper: {ub})")

    rand_values = get_uniform(min=lb, max=ub).rvs(size)
    print(f"Observed range: {int(round(rand_values.min(), 0))} to {int(round(rand_values.max(), 0))}")
    print()

Which gives:

Experiment (Lower: 5000, Upper: 10000)
Observed range: 5000 to 10000

Experiment (Lower: -10000, Upper: -5000)
Observed range: -10000 to -5000

Experiment (Lower: -1000, Upper: 0)
Observed range: -1000 to 0

Experiment (Lower: 0, Upper: 1000)
Observed range: 0 to 1000

Which is exactly as you would expect.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Anton K
Solution 3 miksus