June 01, 2012
Unevenly Weighted Random Numbers
A couple of weeks ago, I wrote about weighted random numbers. After implementation and some experimentation, I settled on a versatile function that incorporates all the fetchers of the weighting system. Mathematically, it's a little ugly because there is an “if” statement and we end up with a piecewise function.
Where m is the minimum value, M is the maximum value, c is the center point (m ≤ c ≤ M), S is the concentration coefficient (useful range 1 ≤ S < ∞), and α and β are random numbers between 0 and 1. The core of this function is the weighting.
This has been scaled so the output is in a given range.
Here, m ≤ ws ≤ M were as 0 ≤ w ≤ 1. From here, the body of the function is split before and after the center point. For this we require a second random number, α. This value is used to determine of the value is to the left or right of center, and the min and max of the function are adjusted accordingly.
Max (M)
Center (c)
Concentration (S)
The top graph shows the distribution of 1,000 samples, and the lower graph shows a histogram of the distribution. The average is calculated over all the samples. If the center value is half-way between min and max, the average should be the center value (or close to). The center value reflects the highest peak value in the histogram, which should always be close to the specified center.
There are some things you can do with this function that are not meaningful. Having a center value outside the min and max value will still generate values, but probably not useful for anything.
You can also use a concentration coefficient less than one and greater than zero (0 ≤ S < ≤ 1) . This has the effect of pushing the concentration away from the center point and toward the min and max values—basically the acting in the reverse of the normal algorithm. This may be useful for generating a value that is usually either one value or an other, with very little in between.
Here the min is 0, max is 100, center is 20, and the concentration coefficient is 0.1. Notice how the center point is the least populated area of the graph.
There are some ways to use this function to generate some of the other weighted functions. For example, let c = ½ (M – m) + m. This will make the function have equal distribution on both sides of the center point.
Here, the function C is a centered function, c is the center point, and s is the span that can be deviated from the center.
For a simple left or right weighted version of the function, simply set the center point to the min value (left weighted) or max value (right weighted).
Using a concentration coefficient of one (S =1) results in just random uniform random data (assuming β is random). Small values of S are harder to notice in this demo, but become pronounced when more samples are used.
Here is an example of a center at 70, min of 0, max of 100, and a concentration coefficient of 2. At 1000 samples it is not apparent there is any concentration, but at 100,000 samples it is easier to see. The higher sample set also makes the histogram more clear. Notice how the histogram falls to around 100 on both sides, but more rapidly to the right of center. This is necessary because of the uneven weight. So a 0 or a 100 are both equally likely (or unlikely as the case may be), but a 60 and 80, despite being equal distance from the center point are not both as likely as one an other (higher likelihood of 60 over 80).
// Return a weighted random number with an uneven distribution from center.
// $min - Smallest possible.
// $max - Largest possible value.
// $center - Location of highest conentration.
// $concentration - How strongly to curve number--the higher the value,
// the strong the curve tends toward center.
// $alpha - Number between 0 and 1, generally random.
// $beta - Number between 0 and 1, generally random.
//----------------------------------------------------------------------------
function uneven( $min, $max, $center, $concentration, $alpha, $beta )
{
// Curve beta.
$numerator = 1 - $beta;
$denominator = $beta * ( $concentration - 1 ) + 1;
$result = $numerator / $denominator;
// Get center point.
$centerDivide = ( $center - $min ) / ( $max - $min );
// Figure out if this result is to the left or right of center.
if ( $alpha < $centerDivide )
{
$result *= $center - $min;
$result = $center - $result;
}
else
{
$result *= $max - $center;
$result += $center;
}
return $result;
}