random.py

来自「mallet是自然语言处理、机器学习领域的一个开源项目。」· Python 代码 · 共 780 行 · 第 1/2 页

PY
780
字号
        """        # mu = mean, sigma = standard deviation        # Uses Kinderman and Monahan method. Reference: Kinderman,        # A.J. and Monahan, J.F., "Computer generation of random        # variables using the ratio of uniform deviates", ACM Trans        # Math Software, 3, (1977), pp257-260.        random = self.random        while 1:            u1 = random()            u2 = 1.0 - random()            z = NV_MAGICCONST*(u1-0.5)/u2            zz = z*z/4.0            if zz <= -_log(u2):                break        return mu + z*sigma## -------------------- lognormal distribution --------------------    def lognormvariate(self, mu, sigma):        """Log normal distribution.        If you take the natural logarithm of this distribution, you'll get a        normal distribution with mean mu and standard deviation sigma.        mu can have any value, and sigma must be greater than zero.        """        return _exp(self.normalvariate(mu, sigma))## -------------------- circular uniform --------------------    def cunifvariate(self, mean, arc):        """Circular uniform distribution.        mean is the mean angle, and arc is the range of the distribution,        centered around the mean angle.  Both values must be expressed in        radians.  Returned values range between mean - arc/2 and        mean + arc/2 and are normalized to between 0 and pi.        Deprecated in version 2.3.  Use:            (mean + arc * (Random.random() - 0.5)) % Math.pi        """        # mean: mean angle (in radians between 0 and pi)        # arc:  range of distribution (in radians between 0 and pi)        return (mean + arc * (self.random() - 0.5)) % _pi## -------------------- exponential distribution --------------------    def expovariate(self, lambd):        """Exponential distribution.        lambd is 1.0 divided by the desired mean.  (The parameter would be        called "lambda", but that is a reserved word in Python.)  Returned        values range from 0 to positive infinity.        """        # lambd: rate lambd = 1/mean        # ('lambda' is a Python reserved word)        random = self.random        u = random()        while u <= 1e-7:            u = random()        return -_log(u)/lambd## -------------------- von Mises distribution --------------------    def vonmisesvariate(self, mu, kappa):        """Circular data distribution.        mu is the mean angle, expressed in radians between 0 and 2*pi, and        kappa is the concentration parameter, which must be greater than or        equal to zero.  If kappa is equal to zero, this distribution reduces        to a uniform random angle over the range 0 to 2*pi.        """        # mu:    mean angle (in radians between 0 and 2*pi)        # kappa: concentration parameter kappa (>= 0)        # if kappa = 0 generate uniform random angle        # Based upon an algorithm published in: Fisher, N.I.,        # "Statistical Analysis of Circular Data", Cambridge        # University Press, 1993.        # Thanks to Magnus Kessler for a correction to the        # implementation of step 4.        random = self.random        if kappa <= 1e-6:            return TWOPI * random()        a = 1.0 + _sqrt(1.0 + 4.0 * kappa * kappa)        b = (a - _sqrt(2.0 * a))/(2.0 * kappa)        r = (1.0 + b * b)/(2.0 * b)        while 1:            u1 = random()            z = _cos(_pi * u1)            f = (1.0 + r * z)/(r + z)            c = kappa * (r - f)            u2 = random()            if not (u2 >= c * (2.0 - c) and u2 > c * _exp(1.0 - c)):                break        u3 = random()        if u3 > 0.5:            theta = (mu % TWOPI) + _acos(f)        else:            theta = (mu % TWOPI) - _acos(f)        return theta## -------------------- gamma distribution --------------------    def gammavariate(self, alpha, beta):        """Gamma distribution.  Not the gamma function!        Conditions on the parameters are alpha > 0 and beta > 0.        """        # alpha > 0, beta > 0, mean is alpha*beta, variance is alpha*beta**2        # Warning: a few older sources define the gamma distribution in terms        # of alpha > -1.0        if alpha <= 0.0 or beta <= 0.0:            raise ValueError, 'gammavariate: alpha and beta must be > 0.0'        random = self.random        if alpha > 1.0:            # Uses R.C.H. Cheng, "The generation of Gamma            # variables with non-integral shape parameters",            # Applied Statistics, (1977), 26, No. 1, p71-74            ainv = _sqrt(2.0 * alpha - 1.0)            bbb = alpha - LOG4            ccc = alpha + ainv            while 1:                u1 = random()                if not 1e-7 < u1 < .9999999:                    continue                u2 = 1.0 - random()                v = _log(u1/(1.0-u1))/ainv                x = alpha*_exp(v)                z = u1*u1*u2                r = bbb+ccc*v-x                if r + SG_MAGICCONST - 4.5*z >= 0.0 or r >= _log(z):                    return x * beta        elif alpha == 1.0:            # expovariate(1)            u = random()            while u <= 1e-7:                u = random()            return -_log(u) * beta        else:   # alpha is between 0 and 1 (exclusive)            # Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle            while 1:                u = random()                b = (_e + alpha)/_e                p = b*u                if p <= 1.0:                    x = pow(p, 1.0/alpha)                else:                    # p > 1                    x = -_log((b-p)/alpha)                u1 = random()                if not (((p <= 1.0) and (u1 > _exp(-x))) or                          ((p > 1)  and  (u1 > pow(x, alpha - 1.0)))):                    break            return x * beta    def stdgamma(self, alpha, ainv, bbb, ccc):        # This method was (and shall remain) undocumented.        # This method is deprecated        # for the following reasons:        # 1. Returns same as .gammavariate(alpha, 1.0)        # 2. Requires caller to provide 3 extra arguments        #    that are functions of alpha anyway        # 3. Can't be used for alpha < 0.5        # ainv = sqrt(2 * alpha - 1)        # bbb = alpha - log(4)        # ccc = alpha + ainv        import warnings        warnings.warn("The stdgamma function is deprecated; "                      "use gammavariate() instead",                      DeprecationWarning)        return self.gammavariate(alpha, 1.0)## -------------------- Gauss (faster alternative) --------------------    def gauss(self, mu, sigma):        """Gaussian distribution.        mu is the mean, and sigma is the standard deviation.  This is        slightly faster than the normalvariate() function.        Not thread-safe without a lock around calls.        """        # When x and y are two variables from [0, 1), uniformly        # distributed, then        #        #    cos(2*pi*x)*sqrt(-2*log(1-y))        #    sin(2*pi*x)*sqrt(-2*log(1-y))        #        # are two *independent* variables with normal distribution        # (mu = 0, sigma = 1).        # (Lambert Meertens)        # (corrected version; bug discovered by Mike Miller, fixed by LM)        # Multithreading note: When two threads call this function        # simultaneously, it is possible that they will receive the        # same return value.  The window is very small though.  To        # avoid this, you have to use a lock around all calls.  (I        # didn't want to slow this down in the serial case by using a        # lock here.)        random = self.random        z = self.gauss_next        self.gauss_next = None        if z is None:            x2pi = random() * TWOPI            g2rad = _sqrt(-2.0 * _log(1.0 - random()))            z = _cos(x2pi) * g2rad            self.gauss_next = _sin(x2pi) * g2rad        return mu + z*sigma## -------------------- beta --------------------## See## http://sourceforge.net/bugs/?func=detailbug&bug_id=130030&group_id=5470## for Ivan Frohne's insightful analysis of why the original implementation:####    def betavariate(self, alpha, beta):##        # Discrete Event Simulation in C, pp 87-88.####        y = self.expovariate(alpha)##        z = self.expovariate(1.0/beta)##        return z/(y+z)#### was dead wrong, and how it probably got that way.    def betavariate(self, alpha, beta):        """Beta distribution.        Conditions on the parameters are alpha > -1 and beta} > -1.        Returned values range between 0 and 1.        """        # This version due to Janne Sinkkonen, and matches all the std        # texts (e.g., Knuth Vol 2 Ed 3 pg 134 "the beta distribution").        y = self.gammavariate(alpha, 1.)        if y == 0:            return 0.0        else:            return y / (y + self.gammavariate(beta, 1.))## -------------------- Pareto --------------------    def paretovariate(self, alpha):        """Pareto distribution.  alpha is the shape parameter."""        # Jain, pg. 495        u = 1.0 - self.random()        return 1.0 / pow(u, 1.0/alpha)## -------------------- Weibull --------------------    def weibullvariate(self, alpha, beta):        """Weibull distribution.        alpha is the scale parameter and beta is the shape parameter.        """        # Jain, pg. 499; bug fix courtesy Bill Arms        u = 1.0 - self.random()        return alpha * pow(-_log(u), 1.0/beta)## -------------------- test program --------------------def _test_generator(n, funccall):    import time    print n, 'times', funccall    code = compile(funccall, funccall, 'eval')    sum = 0.0    sqsum = 0.0    smallest = 1e10    largest = -1e10    t0 = time.time()    for i in range(n):        x = eval(code)        sum = sum + x        sqsum = sqsum + x*x        smallest = min(x, smallest)        largest = max(x, largest)    t1 = time.time()    print round(t1-t0, 3), 'sec,',    avg = sum/n    stddev = _sqrt(sqsum/n - avg*avg)    print 'avg %g, stddev %g, min %g, max %g' % \              (avg, stddev, smallest, largest)def _test(N=20000):    print 'TWOPI         =', TWOPI    print 'LOG4          =', LOG4    print 'NV_MAGICCONST =', NV_MAGICCONST    print 'SG_MAGICCONST =', SG_MAGICCONST    _test_generator(N, 'random()')    _test_generator(N, 'normalvariate(0.0, 1.0)')    _test_generator(N, 'lognormvariate(0.0, 1.0)')    _test_generator(N, 'cunifvariate(0.0, 1.0)')    _test_generator(N, 'expovariate(1.0)')    _test_generator(N, 'vonmisesvariate(0.0, 1.0)')    _test_generator(N, 'gammavariate(0.01, 1.0)')    _test_generator(N, 'gammavariate(0.1, 1.0)')    _test_generator(N, 'gammavariate(0.1, 2.0)')    _test_generator(N, 'gammavariate(0.5, 1.0)')    _test_generator(N, 'gammavariate(0.9, 1.0)')    _test_generator(N, 'gammavariate(1.0, 1.0)')    _test_generator(N, 'gammavariate(2.0, 1.0)')    _test_generator(N, 'gammavariate(20.0, 1.0)')    _test_generator(N, 'gammavariate(200.0, 1.0)')    _test_generator(N, 'gauss(0.0, 1.0)')    _test_generator(N, 'betavariate(3.0, 3.0)')    _test_generator(N, 'paretovariate(1.0)')    _test_generator(N, 'weibullvariate(1.0, 1.0)')    # Test jumpahead.    s = getstate()    jumpahead(N)    r1 = random()    # now do it the slow way    setstate(s)    for i in range(N):        random()    r2 = random()    if r1 != r2:        raise ValueError("jumpahead test failed " + `(N, r1, r2)`)# Create one instance, seeded from current time, and export its methods# as module-level functions.  The functions are not threadsafe, and state# is shared across all uses (both in the user's code and in the Python# libraries), but that's fine for most programs and is easier for the# casual user than making them instantiate their own Random() instance._inst = Random()seed = _inst.seedrandom = _inst.randomuniform = _inst.uniformrandint = _inst.randintchoice = _inst.choicerandrange = _inst.randrangeshuffle = _inst.shufflenormalvariate = _inst.normalvariatelognormvariate = _inst.lognormvariatecunifvariate = _inst.cunifvariateexpovariate = _inst.expovariatevonmisesvariate = _inst.vonmisesvariategammavariate = _inst.gammavariatestdgamma = _inst.stdgammagauss = _inst.gaussbetavariate = _inst.betavariateparetovariate = _inst.paretovariateweibullvariate = _inst.weibullvariategetstate = _inst.getstatesetstate = _inst.setstatejumpahead = _inst.jumpaheadwhseed = _inst.whseedif __name__ == '__main__':    _test()

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?