Home > Software engineering >  Is there a way to generate random numbers with a large range, but tend towards values near 1? (Java)
Is there a way to generate random numbers with a large range, but tend towards values near 1? (Java)

Time:05-11

I'm making a neural network and I have a variable weight that is multiplied with some value. I want to be able to randomize the weight variable and allow it to be decimals like 0.1 or large numbers like up to 10. However, I want it to usually be closer to 1 than not.

Here's an example of what I want the randomized values to look like:

0.9, 0.6, 1.5, 0.2, 5.8, 1.1, 1.3, 0.8, 2.6, etc.

Values such as 5.8 are allowed, but most are near 1.

Please let me know if this is possible to do in Java.

Thank you very much!

CodePudding user response:

It sounds like you want a Poisson distribution. Normally the distribution of values is discrete, given by whole number, e.g. 0, 1, 2, etc., but you can divide a result by 10 to get one decimal place.

The probability function of a Poisson random variable x is given by the formula:

f(x) =(e–λ λx)/x!

Java doesn't have anything built-in to get a random variable for a Poisson distribution, but we can get a uniform random variable with Random.nextDouble().

The trick will be to map a uniform random variable to a Poisson random variable.

This Q&A over at Math.se shows using math how to map a uniform random variable to a Poisson random variable by finding the minimum Poisson random variable p that satisfies a condition, where U is the uniform random variable, the condition being that U is less than or equal to the cumulative probability distribution as a function of p.

                                                           p

P ≡ min { p = 0, 1, 2, ... | U ≤ exp(-λ) Σ (λp)/p! }

                                                          i=0

Here's some code I wrote using this equation to convert a uniform random variable urv to a Poisson random variable p.

public class Test {
    public static void main(String[] args) {
        double lambda = 10.0;
        System.out.println("Test");
        for (int urv100 = 0; urv100 < 100; urv100  ) {
            double urv = urv100 / 100.0;
            System.out.println("P("   lambda   ", "   urv   ") = "   poisson(lambda, urv));
        }
        System.out.println("Converting uniform to Poisson");
        Random rnd = new Random();
        for (int r = 0; r < 100; r  ) {
            double urv = rnd.nextDouble();
            System.out.println("urv of "   urv   " mapped to p of "   poisson(lambda, urv) / 10.0);
        }
        System.out.println("urv of 0.999999 mapped to p of "   poisson(lambda, 0.999999) / 10.0);
        System.out.println("urv of 0.999999999999 mapped to p of "   poisson(lambda, 0.999999999999) / 10.0);
        //System.out.println("urv of 0.9999999999999999 mapped to p of "   poisson(lambda, 0.9999999999999999) / 10.0);
    }
    public static int poisson(double lambda, double urv){
        int p = 0;
        while (true) {
            double cumulDistr = cumulDistr(lambda, p);
            //System.out.println("   cumulDistr("   lambda   ", "   p   ") is "   cumulDistr);
            if (urv <= cumulDistr) {
                return p;
            }
            p  ;
        }
    }

    private static double cumulDistr(double lambda, int p) {
        double summation = 0;
        for (int i = 0; i <= p; i  ) {
            summation  = Math.pow(lambda, i) / fact(i);
        }
        return summation * Math.exp(-lambda);
    }

    private static double fact(int p) {
        double product = 1;
        for (int f = 1; f <= p; f  ) {
            product *= f;
        }
        return product;
    }
}

The fact method calculates factorials, the cumulDistr method calculates the cumulative Poisson distribution, and the poisson method calculates the minimum p such that urv is less than or equal to the cumulative distribution. The lambda variable is the mean of the Poisson distribution.

If you want a mean of 1.0, but discrete values in increments of 0.1, then make lambda 10 and divide your result by 10.

Here's my output. Note that while 5.8 may be possible, it may be exceedingly rare.

Test
P(10.0, 0.0) = 0
P(10.0, 0.01) = 3
P(10.0, 0.02) = 4
P(10.0, 0.03) = 5
P(10.0, 0.04) = 5
P(10.0, 0.05) = 5
P(10.0, 0.06) = 5
P(10.0, 0.07) = 6
P(10.0, 0.08) = 6
P(10.0, 0.09) = 6
P(10.0, 0.1) = 6
P(10.0, 0.11) = 6
P(10.0, 0.12) = 6
P(10.0, 0.13) = 6
P(10.0, 0.14) = 7
P(10.0, 0.15) = 7
P(10.0, 0.16) = 7
P(10.0, 0.17) = 7
P(10.0, 0.18) = 7
P(10.0, 0.19) = 7
P(10.0, 0.2) = 7
P(10.0, 0.21) = 7
P(10.0, 0.22) = 7
P(10.0, 0.23) = 8
P(10.0, 0.24) = 8
P(10.0, 0.25) = 8
P(10.0, 0.26) = 8
P(10.0, 0.27) = 8
P(10.0, 0.28) = 8
P(10.0, 0.29) = 8
P(10.0, 0.3) = 8
P(10.0, 0.31) = 8
P(10.0, 0.32) = 8
P(10.0, 0.33) = 8
P(10.0, 0.34) = 9
P(10.0, 0.35) = 9
P(10.0, 0.36) = 9
P(10.0, 0.37) = 9
P(10.0, 0.38) = 9
P(10.0, 0.39) = 9
P(10.0, 0.4) = 9
P(10.0, 0.41) = 9
P(10.0, 0.42) = 9
P(10.0, 0.43) = 9
P(10.0, 0.44) = 9
P(10.0, 0.45) = 9
P(10.0, 0.46) = 10
P(10.0, 0.47) = 10
P(10.0, 0.48) = 10
P(10.0, 0.49) = 10
P(10.0, 0.5) = 10
P(10.0, 0.51) = 10
P(10.0, 0.52) = 10
P(10.0, 0.53) = 10
P(10.0, 0.54) = 10
P(10.0, 0.55) = 10
P(10.0, 0.56) = 10
P(10.0, 0.57) = 10
P(10.0, 0.58) = 10
P(10.0, 0.59) = 11
P(10.0, 0.6) = 11
P(10.0, 0.61) = 11
P(10.0, 0.62) = 11
P(10.0, 0.63) = 11
P(10.0, 0.64) = 11
P(10.0, 0.65) = 11
P(10.0, 0.66) = 11
P(10.0, 0.67) = 11
P(10.0, 0.68) = 11
P(10.0, 0.69) = 11
P(10.0, 0.7) = 12
P(10.0, 0.71) = 12
P(10.0, 0.72) = 12
P(10.0, 0.73) = 12
P(10.0, 0.74) = 12
P(10.0, 0.75) = 12
P(10.0, 0.76) = 12
P(10.0, 0.77) = 12
P(10.0, 0.78) = 12
P(10.0, 0.79) = 12
P(10.0, 0.8) = 13
P(10.0, 0.81) = 13
P(10.0, 0.82) = 13
P(10.0, 0.83) = 13
P(10.0, 0.84) = 13
P(10.0, 0.85) = 13
P(10.0, 0.86) = 13
P(10.0, 0.87) = 14
P(10.0, 0.88) = 14
P(10.0, 0.89) = 14
P(10.0, 0.9) = 14
P(10.0, 0.91) = 14
P(10.0, 0.92) = 15
P(10.0, 0.93) = 15
P(10.0, 0.94) = 15
P(10.0, 0.95) = 15
P(10.0, 0.96) = 16
P(10.0, 0.97) = 16
P(10.0, 0.98) = 17
P(10.0, 0.99) = 18
Converting uniform to Poisson
urv of 0.8288520112341562 mapped to p of 1.3
urv of 0.35446366155650744 mapped to p of 0.9
urv of 0.8340486798727402 mapped to p of 1.3
urv of 0.8858928268763592 mapped to p of 1.4
urv of 0.9026643406946203 mapped to p of 1.4
urv of 0.13960555377413952 mapped to p of 0.7
urv of 0.9195710056013893 mapped to p of 1.5
urv of 0.44998928169297736 mapped to p of 0.9
urv of 0.8793009483663888 mapped to p of 1.4
urv of 0.8591855177365383 mapped to p of 1.3
urv of 0.5205437915100812 mapped to p of 1.0
urv of 0.8703983622023188 mapped to p of 1.4
urv of 0.82075096895357 mapped to p of 1.3
urv of 0.9806363370196562 mapped to p of 1.7
urv of 0.02509517057275079 mapped to p of 0.4
urv of 0.36375516077339465 mapped to p of 0.9
urv of 0.07037727036002717 mapped to p of 0.6
urv of 0.6818190760646871 mapped to p of 1.1
urv of 0.32197145361627577 mapped to p of 0.8
urv of 0.23745234391089698 mapped to p of 0.8
urv of 0.8934052227696372 mapped to p of 1.4
urv of 0.44142256004343283 mapped to p of 0.9
urv of 0.4021584936656427 mapped to p of 0.9
urv of 0.8982224754947559 mapped to p of 1.4
urv of 0.5358391491707077 mapped to p of 1.0
urv of 0.7385630250167211 mapped to p of 1.2
urv of 0.979775968296643 mapped to p of 1.7
urv of 0.22274327853351406 mapped to p of 0.8
urv of 0.07561592409103857 mapped to p of 0.6
urv of 0.06473994682056239 mapped to p of 0.5
urv of 0.5416987364902209 mapped to p of 1.0
urv of 0.4860980118260786 mapped to p of 1.0
urv of 0.9564072685131361 mapped to p of 1.6
urv of 0.19446735227769363 mapped to p of 0.7
urv of 0.7675862499420885 mapped to p of 1.2
urv of 0.4277105215574004 mapped to p of 0.9
urv of 0.8923336944675764 mapped to p of 1.4
urv of 0.9353143574875429 mapped to p of 1.5
urv of 0.5754775563481273 mapped to p of 1.0
urv of 0.449414823264646 mapped to p of 0.9
urv of 0.9109544383075693 mapped to p of 1.4
urv of 0.3837527451770203 mapped to p of 0.9
urv of 0.14283575366272117 mapped to p of 0.7
urv of 0.3866077468484732 mapped to p of 0.9
urv of 0.662249698097005 mapped to p of 1.1
urv of 0.05012298208977162 mapped to p of 0.5
urv of 0.12890274868435359 mapped to p of 0.6
urv of 0.7709717413863731 mapped to p of 1.2
urv of 0.7629124932757383 mapped to p of 1.2
urv of 0.08419512530357443 mapped to p of 0.6
urv of 0.9814512014328213 mapped to p of 1.7
urv of 0.01204516066988126 mapped to p of 0.4
urv of 0.8681197289737762 mapped to p of 1.4
urv of 0.2322137137936654 mapped to p of 0.8
urv of 0.6494975804996993 mapped to p of 1.1
urv of 0.4649550027050112 mapped to p of 1.0
urv of 0.36705272690857005 mapped to p of 0.9
urv of 0.08698141252662916 mapped to p of 0.6
urv of 0.24326648103541826 mapped to p of 0.8
urv of 0.9229172381814946 mapped to p of 1.5
urv of 0.08379005168736153 mapped to p of 0.6
urv of 0.6544487613989808 mapped to p of 1.1
urv of 0.18367321169511808 mapped to p of 0.7
urv of 0.6756484363119853 mapped to p of 1.1
urv of 0.13179611575336148 mapped to p of 0.7
urv of 0.2534425428679633 mapped to p of 0.8
urv of 0.16581779859681034 mapped to p of 0.7
urv of 0.9086216315426554 mapped to p of 1.4
urv of 0.11808111111941566 mapped to p of 0.6
urv of 0.28957878822961225 mapped to p of 0.8
urv of 0.8244607265851857 mapped to p of 1.3
urv of 0.8831380495463445 mapped to p of 1.4
urv of 0.2222095479898628 mapped to p of 0.8
urv of 0.5000703942445024 mapped to p of 1.0
urv of 0.3341765268545145 mapped to p of 0.9
urv of 0.033476169064498684 mapped to p of 0.5
urv of 0.2856853641247886 mapped to p of 0.8
urv of 0.8530540470203735 mapped to p of 1.3
urv of 0.3028587949037277 mapped to p of 0.8
urv of 0.8449176275299684 mapped to p of 1.3
urv of 0.9388444379027909 mapped to p of 1.5
urv of 0.403224473163457 mapped to p of 0.9
urv of 0.22447582249839637 mapped to p of 0.8
urv of 0.13523963178706166 mapped to p of 0.7
urv of 0.9652355645124876 mapped to p of 1.6
urv of 0.05497837319494847 mapped to p of 0.5
urv of 0.44545341748361267 mapped to p of 0.9
urv of 0.15230147439015596 mapped to p of 0.7
urv of 0.5575736794499111 mapped to p of 1.0
urv of 0.3649349046306235 mapped to p of 0.9
urv of 0.06878741747556394 mapped to p of 0.6
urv of 0.7216428916513631 mapped to p of 1.2
urv of 0.8546996873563696 mapped to p of 1.3
urv of 0.22761255830658056 mapped to p of 0.8
urv of 0.47096564927387896 mapped to p of 1.0
urv of 0.5305503681123561 mapped to p of 1.0
urv of 0.1655836111058504 mapped to p of 0.7
urv of 0.5312078242229661 mapped to p of 1.0
urv of 0.1390046501481954 mapped to p of 0.7
urv of 0.5188365074236052 mapped to p of 1.0
urv of 0.999999 mapped to p of 2.8
urv of 0.999999999999 mapped to p of 3.9

Note that in trying to get a 5.8, I tried 0.9999999999999999 (16 9 decimal digits). It ran for over a minute before I killed it. It must have run up against the precision of a double for the cumulative distribution value, so you'll have to add some kind of guard against this edge case.

You may also want to set lambda to 5.0 and divide the result by 5 to values in increments of 0.2, which may widen the probability curve enough to (occasionally) get a 5.8.

CodePudding user response:

You do this by giving the randomizer more low values than high values. Set up an array which holds your weight values, with more low values than high values. Then the randomizer creates an index. Since you have more low values, then the chances of a low value being selected is greater than a high value:

float[] values = new float[5];
values[0] = 0.1f;
values[1] = 0.1f;
values[2] = 0.2f;
values[3] = 0.2f;
values[4] = 10.0f;

The randomizer returns indexes from 0 to 4. The value of 0.1 and 0.2 are twice as likely to be chosen than 10.0

You adjust the weight by adding more low values than high values.

CodePudding user response:

You could take a value from the function 10 - log(x) for x from 1 to e^10.

This would give you values from 0 to 10 that are much more likely to be low than high.

Random r = new Random();
double max = Math.exp(10);

public double expWeight() {
    return 10 - Math.log(r.nextDouble(1, max));
}

double weight = expWeight();

However, this will also make numbers smaller than 1 even more likely than 1, which may not be what you are looking for.

  • Related