Generating random numbers from a distorted normal distribution

when you use random (min, max) function in most languages, what is the distribution?

what if I want to create a range of numbers within 20% of the time and another range of numbers in 80% of cases, how can I generate a sequence of random number that follows this?

ex), I have to get a random frequency, but the frequency "1" should be about 20% higher than the frequency "0"

+4
source share
9 answers

Most pseudo-random generators of embedded programming languages ​​provide uniform distribution , that is, each value within the range has the same probability of being produced as any other value in the range. Indeed, in some cases, this requirement is part of the locale. Some languages, such as Python or R, support various common distributions.

If the language does not support it, you need to either use math tricks to create other distributions, such as a normal distribution from one, or you can look for third-party libraries that perform this function.

Your problem seems a lot simpler because the random variable is discrete (and a simpler type, i.e. binary). The trick for them is to create a random number that forms a uniform distribution in a given range, say from 0 to 999, and divide this range in the proportions associated with each value, in this case it will be something like this: / p>

If (RandomNumber) < 200 // 20% RandomVariable = 0 Else // 80% RandomVariable = 1 

This logic, of course, can be applied to n discrete variables.

+1
source

For most languages, the random number generated may depend on the algorithm within that language or be randomly generated based on several factors, such as time, processor, number of seeds.

The distribution is not normal. In fact, if a function returns 5 integers, all 5 integers have a sufficient probability of occurrence in the next function call. This is also known as uniform distribution.

So, tell me if you want to produce a number (for example, 7) within 20% of the time, and another number (say 13) within 80% of the time, you can make such an array:

 var arr = [7,13,13,13,13]; var picked = arr[Math.floor(Math.random()*arr.length)] ; // since Math.random() returns a float from 0.0 to 1.0 

Thus, 7 has a 20% chance of occurrence, and 13 has a probability of 80%.

+1
source

This is one of the possible ways:

 ranges = [(10..15), (20..30)] selector = [0, 0, 1,1,1,1,1,1,1,1] # 80:20 distribution array # now select a range randomly random_within_range(ranges(selector[random(10)])) def random_within_range range rand (range.last - range.begin - (range.exclude_end? ? 1 : 0)) + range.begin end 
+1
source

Your question is slightly different from your example. Therefore, I will answer both questions, and you can find out what answers you are really looking for.

1) Your example (I don't know ruby ​​or java, so bear with me)

  • First, create a random number from a uniform distribution from 0 to 1, call it X.
  • Then you can set if / else (that is, if (x <.2) {1} else {0})

2) Generation of random numbers from the normal distribution with a braid

  • You can look at distorted distributions, such as the skewed distribution of T students with a high degree of freedom.
  • You can also use regular CDF and just select numbers that way.
  • Here's an article discussing how to do this with multiple random numbers from a uniform distribution
  • Finally, you can use a nonparametric approach, which will include estimating the core density (I suspect you're not looking for anything so complicated).
+1
source

Like any person, the pseudo-random number generator in most languages ​​implements a uniform distribution over (0,1). If you have two categories of answers (0,1) with probability p for 1, you have a Bernoulli distribution and can be emulated with

 # returns 1 with p probability and 0 with (1-p) probability def bernoulli(p) rand()<p ? 1:0; end 

Simply. A skewed normal distribution is a completely different beast created by a “union” of pdf and cdf normal distribution to create skew. You can read Azzalini's work here . Using the distribution of gems, you can generate a probability density function using

 # require 'distribution' def sn_pdf(x,alpha) sp = 2*Distribution::Normal.pdf(x)*Distribution::Normal.cdf(x*alpha) end 

Getting cdf is difficult because there is no analytic solution, so you have to integrate it. To get random numbers from distorted normal, you can use the accept-reject algorithm.

+1
source

Most computer languages ​​have a uniform distribution of their (pseudo) random integer generators. Thus, each integer is equally likely.

For your example, suppose you want "1" 55% of the time and "0" 45% of the time.

To get these frequencies unequal, try creating a random number from 1 to 100. If the number is generated from 1 to 55, print "1"; otherwise the output is "0".

0
source

What about

 var oneFreq = 80.0/100.0; var output = 0; if (Math.random() > oneFreq) output = 1; 

or, if you want 20% of the values ​​to be between 0 and 100, and 80% should be between 100 and 200.

 var oneFreq = 80.0/100.0; var oneRange = 100; var zeroRange = 100; var output = Math.random(); if (output > oneFreq) output = zeroRange + Math.floor(oneRange * (output - oneFreq)); else output = Math.floor(zeroRange * output); 
0
source

Check out this lecture if you want a good mathematical understanding.

0
source

In ruby, I would do it like this:

 class DistributedRandom def initialize(left, right = nil) if right @distribution = [0] * left + [1] * right else @distribution = left end end def get @distribution[rand @distribution.length] end end 

Running a test with an 80:20 distribution:

 test = [0,0] rnd = DistributedRandom.new 80, 20 # 80:20 distribution 10000.times { test[rnd.get] += 1 }; puts "Test 1", test 

Running the test with a 20% distribution on the right side:

 test = [0,0] rnd = DistributedRandom.new 100, 120 # +20% distribution 10000.times { test[rnd.get] += 1 }; puts "Test 2", test 

Running a test with a user-defined distribution with a trigonometric function across 91 discrete values, however, the result does not fit very well in previous tests:

 test = [0,0] rnd = DistributedRandom.new((0..90).map {|x| Math.sin(Math::PI * x / 180.0)}) 10000.times { test[rnd.get] += 1 }; puts "Test 3", test 
0
source

Source: https://habr.com/ru/post/1303369/


All Articles