2

I want to generate random float variables in python with the following characteristics:

  • The domain is [0,1] (or very close to it)
  • The mean isn't always 0.5, and it should be between [0,1]

Clearly, it's definitely a skewed distribution. I've experimented with scaled skewed normal distributions in scipy without getting what I want.

Let's say I want to create a vector of these random variables by calling a function with one or more parameters that set the shape of the distribution. Is there a distribution that has the above characteristics? If it's already in numpy or scipy that would be a bonus.

NB: It would be nice if I could independently set the width of the skewed distribution, but if not that would be OK (e.g., if the width depended on the mean).

EDIT: I want to generate multiple ensembles of random variables. For each ensemble, I tried randomizing the skew parameter to try and get a different mean. It sort of worked, but I wasn't happy with the results after I tried scaling the distribution such that the random variables would be between [0,1].

Nick Elias
  • 61
  • 5
  • Does this help? https://stackoverflow.com/questions/36200913/generate-n-random-numbers-from-a-skew-normal-distribution-using-numpy – learner Oct 25 '22 at 00:13
  • can you be a bit more specific about distribution properties? Because right now `return mean` will do it UPD: at the very least, say a word or two about variance – Marat Oct 25 '22 at 00:17
  • @learner: I've tried using the skewnormal distribution (see edit above), and I wasn't happy with the results. – Nick Elias Oct 25 '22 at 18:02
  • @Marat I haven't been worrying too much variance. At this point, I would take almost any variance if the distribution gave be something usable between [0,1]. – Nick Elias Oct 25 '22 at 18:06

1 Answers1

1

I'm not sure if this is exactly what you're looking for, but you could try using random.triangular. According to the documentation, the default arguments result in a symmetric distribution with values between 0 and 1. However, if we change mode, we can generate a skewed distribution:

def generate_random(m, length):
    return [random.triangular(mode = m) for _ in range(length)]

Here are some test results (your mileage may vary):

sum(generate_random(0.6, 10000)) / 10000  # 0.52 - 0.53
sum(generate_random(0.7, 10000)) / 10000  # 0.56 - 0.57
sum(generate_random(0.8, 10000)) / 10000  # 0.59 - 0.60
sum(generate_random(0.9, 10000)) / 10000  # 0.63 - 0.64
sum(generate_random(1.0, 10000)) / 10000  # 0.66 - 0.67
Woody1193
  • 7,252
  • 5
  • 40
  • 90
  • It never occurred to me to use a triangular distribution. This distribution looks promising. I can enforce a strict [0,1] domain and get different means. I would have preferred a smoother distribution, but I think I can use this. I will give it a try. Thanks! – Nick Elias Oct 25 '22 at 18:20
  • I tried it. It's not bad. I will do more experimenting. – Nick Elias Oct 25 '22 at 18:41
  • 1
    @NickElias If you want something smoother, average a few triangulars. That will preserve the mean but yield a smoother curve. Another possibility is the [beta distribution](https://en.wikipedia.org/wiki/Beta_distribution), which has a domain [0,1] but can be tuned to a fare-thee-well using two parameters. – pjs Oct 25 '22 at 20:44
  • @pjs I haven't had to do any statistics in about 6 years so I had forgotten about the Beta distribution. What parameters would you submit for alpha and beta to generate what the OP is asking for (say a mean of 0.7 for example)? – Woody1193 Oct 25 '22 at 23:52
  • 1
    @Woody1193 if you check the Wikipedia page, you’ll see that there are many possible solutions for a given mean since the mean is equal to `alpha / (alpha + beta)`. – pjs Oct 26 '22 at 04:15
  • @pjs So, if I wanted an arbitrary mean, I could set `alpha = mean` and then set `beta = 1 - alpha`. And that would certainly be smoother than a triangular distribution. – Woody1193 Oct 26 '22 at 04:19
  • I hadn't thought of the beta distribution for years. I'll give it a try. Thanks! – Nick Elias Oct 28 '22 at 15:34