Spaces:
Sleeping
Sleeping
| """ | |
| Utilities for generating random numbers, random sequences, and | |
| random selections. | |
| """ | |
| import networkx as nx | |
| from networkx.utils import py_random_state | |
| __all__ = [ | |
| "powerlaw_sequence", | |
| "zipf_rv", | |
| "cumulative_distribution", | |
| "discrete_sequence", | |
| "random_weighted_sample", | |
| "weighted_choice", | |
| ] | |
| # The same helpers for choosing random sequences from distributions | |
| # uses Python's random module | |
| # https://docs.python.org/3/library/random.html | |
| def powerlaw_sequence(n, exponent=2.0, seed=None): | |
| """ | |
| Return sample sequence of length n from a power law distribution. | |
| """ | |
| return [seed.paretovariate(exponent - 1) for i in range(n)] | |
| def zipf_rv(alpha, xmin=1, seed=None): | |
| r"""Returns a random value chosen from the Zipf distribution. | |
| The return value is an integer drawn from the probability distribution | |
| .. math:: | |
| p(x)=\frac{x^{-\alpha}}{\zeta(\alpha, x_{\min})}, | |
| where $\zeta(\alpha, x_{\min})$ is the Hurwitz zeta function. | |
| Parameters | |
| ---------- | |
| alpha : float | |
| Exponent value of the distribution | |
| xmin : int | |
| Minimum value | |
| seed : integer, random_state, or None (default) | |
| Indicator of random number generation state. | |
| See :ref:`Randomness<randomness>`. | |
| Returns | |
| ------- | |
| x : int | |
| Random value from Zipf distribution | |
| Raises | |
| ------ | |
| ValueError: | |
| If xmin < 1 or | |
| If alpha <= 1 | |
| Notes | |
| ----- | |
| The rejection algorithm generates random values for a the power-law | |
| distribution in uniformly bounded expected time dependent on | |
| parameters. See [1]_ for details on its operation. | |
| Examples | |
| -------- | |
| >>> nx.utils.zipf_rv(alpha=2, xmin=3, seed=42) | |
| 8 | |
| References | |
| ---------- | |
| .. [1] Luc Devroye, Non-Uniform Random Variate Generation, | |
| Springer-Verlag, New York, 1986. | |
| """ | |
| if xmin < 1: | |
| raise ValueError("xmin < 1") | |
| if alpha <= 1: | |
| raise ValueError("a <= 1.0") | |
| a1 = alpha - 1.0 | |
| b = 2**a1 | |
| while True: | |
| u = 1.0 - seed.random() # u in (0,1] | |
| v = seed.random() # v in [0,1) | |
| x = int(xmin * u ** -(1.0 / a1)) | |
| t = (1.0 + (1.0 / x)) ** a1 | |
| if v * x * (t - 1.0) / (b - 1.0) <= t / b: | |
| break | |
| return x | |
| def cumulative_distribution(distribution): | |
| """Returns normalized cumulative distribution from discrete distribution.""" | |
| cdf = [0.0] | |
| psum = sum(distribution) | |
| for i in range(len(distribution)): | |
| cdf.append(cdf[i] + distribution[i] / psum) | |
| return cdf | |
| def discrete_sequence(n, distribution=None, cdistribution=None, seed=None): | |
| """ | |
| Return sample sequence of length n from a given discrete distribution | |
| or discrete cumulative distribution. | |
| One of the following must be specified. | |
| distribution = histogram of values, will be normalized | |
| cdistribution = normalized discrete cumulative distribution | |
| """ | |
| import bisect | |
| if cdistribution is not None: | |
| cdf = cdistribution | |
| elif distribution is not None: | |
| cdf = cumulative_distribution(distribution) | |
| else: | |
| raise nx.NetworkXError( | |
| "discrete_sequence: distribution or cdistribution missing" | |
| ) | |
| # get a uniform random number | |
| inputseq = [seed.random() for i in range(n)] | |
| # choose from CDF | |
| seq = [bisect.bisect_left(cdf, s) - 1 for s in inputseq] | |
| return seq | |
| def random_weighted_sample(mapping, k, seed=None): | |
| """Returns k items without replacement from a weighted sample. | |
| The input is a dictionary of items with weights as values. | |
| """ | |
| if k > len(mapping): | |
| raise ValueError("sample larger than population") | |
| sample = set() | |
| while len(sample) < k: | |
| sample.add(weighted_choice(mapping, seed)) | |
| return list(sample) | |
| def weighted_choice(mapping, seed=None): | |
| """Returns a single element from a weighted sample. | |
| The input is a dictionary of items with weights as values. | |
| """ | |
| # use roulette method | |
| rnd = seed.random() * sum(mapping.values()) | |
| for k, w in mapping.items(): | |
| rnd -= w | |
| if rnd < 0: | |
| return k | |