2

In passing someone had suggested to me that I could use half normal distribution in python to set min and max points using 0 to infinity: halfnorm.rvs()

The 0 seems to cut off the min, however I have no idea what to do with the infinity.

I would like to do a number generator from 0 - 15 within a normal distribution, but having a hard time finding a function that doesn't go over the max or below the min due to the nature of distribution limits.

Angel Cloudwalker
  • 2,015
  • 5
  • 32
  • 54
  • I agree with you that a normal distribution per definition doesn't have a finite boundary, and then even the half normal distribution is not a normal distribution any more. Then the questions is really what you'd like to use it for. – Dr. V Jun 13 '20 at 19:15
  • I'm simulating a person's reaction times in sports where for example 0 would be instant. – Angel Cloudwalker Jun 13 '20 at 19:20
  • So it doesn't have to be a normal distribution... Have a look here: https://en.wikipedia.org/wiki/List_of_probability_distributions ... interesting .. I will have a look too. – Dr. V Jun 13 '20 at 19:22
  • Probability distribution of reaction times: https://www.researchgate.net/figure/A-Probability-distribution-of-reaction-times-aggregated-across-all-subjects-showing_fig2_5760738 It looks like lognormal: https://en.wikipedia.org/wiki/Log-normal_distribution – kol Jun 13 '20 at 19:40

3 Answers3

2

I would try to use the beta-distribution: https://en.wikipedia.org/wiki/Beta_distribution. It's quite simple (e.g. to integrate) and capable of fitting typical reaction time distributions.

Now the question is how to sample this efficiently for fixed α and β parameters ... scipy has done it for us: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.beta.html

Edit: Motivated by the comment and curiosity, here an example, plotting the histogram of 10 samples á 1000 values:

from scipy.stats import beta
from numpy import histogram
import pylab

max_time = 3
min_time = 0.5

a, b = 2, 7
dist = beta(a, b)

for _ in range(10):
    sample = min_time + dist.rvs(size=1000) * (max_time - min_time)
    his, bins = histogram(sample, bins=20, density=True)
    pylab.plot(bins[:-1], his, ".")
pylab.xlabel("Reaction time [s]")
pylab.ylabel("Probability density [1/s]")
pylab.grid()
pylab.show()

enter image description here

Dr. V
  • 1,747
  • 1
  • 11
  • 14
  • thanks, I will try to create a reprex in python using the min and maxes from the original question, unless you or someone else beats me to it lol. – Angel Cloudwalker Jun 13 '20 at 19:53
  • To keep your answer I won't put another answer with code (feel free to put a REPREX though). I did find that the distribution was much better and can be a viable solution. – Angel Cloudwalker Jun 13 '20 at 20:24
0

I had just answered similar question here. I'll copy answer here as I think this question title is much more informative:

You can use uniform distribution with boundaries "translated" from normal to uniform space (using error function) and convert it to normal distribution using inverse error function.

import matplotlib.pyplot as plt
import numpy as np
from scipy import special

mean = 0
std = 7
min_value = 0
max_value = 15

min_in_standard_domain = (min_value - mean) / std
max_in_standard_domain = (max_value - mean) / std

min_in_erf_domain = special.erf(min_in_standard_domain)
max_in_erf_domain = special.erf(max_in_standard_domain)

random_uniform_data = np.random.uniform(min_in_erf_domain, max_in_erf_domain, 10000)
random_gaussianized_data = (special.erfinv(random_uniform_data) * std) + mean
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
axes[0].hist(random_uniform_data, 30)
axes[1].hist(random_gaussianized_data, 30)
axes[0].set_title('uniform distribution samples')
axes[1].set_title('erfinv(uniform distribution samples)')
plt.show()

enter image description here

dankal444
  • 3,172
  • 1
  • 23
  • 35
-1

I recently ran in to a similar issue.

To get around this and keep my min/max in reasonable bounds I just created some if statements to catch any numbers that went above the real min and max.

if value <0:
    value = abs(value)
elif value >15:
    value - 15 = diff
    value = 15-diff

This was close enough for me.

keen21
  • 1
  • 1