Source code for access.weights

import numpy as np


[docs]def step_fn(step_dict): """ Create a step function from a dictionary. Parameters ---------- step_dict : dict Dictionary of cut-offs and weight values. Returns ------- weight_function : function Function returning weight, for input distance or time, *x*. Values beyond the largest threshold will return 0. Examples -------- Import the weights: >>> from access import weights Create a step function with thresholds at 20, 40, and 60. Travel costs are in minutes here, but the code cannot tell if you mix units! >>> fn = weights.step_fn({20 : 1, 40 : 0.68, 60 : 0.22}) >>> {v : fn(v) for v in range(0, 71, 10)} {0: 1, 10: 1, 20: 1, 30: 0.68, 40: 0.68, 50: 0.22, 60: 0.22, 70: 0} """ if type(step_dict) != dict: raise TypeError("step_dict must be of type dict.") for v in step_dict.values(): if v < 0: raise ValueError("All weights must be positive.") def helper(key_to_test): for k, v in sorted(step_dict.items()): if key_to_test <= k: return v return 0 return helper
[docs]def gaussian(sigma): """ Create a gaussian weight function, for a specified width, :math:`\sigma`. The mean / location parameter is assumed to be 0. Note that the standard normalization of the Gaussian, :math:`1 / \sqrt{2\pi\sigma^2}`, is *not* applied, so :math:`f(0) = 1` regardless of the value of :math:`\sigma`. Of course, this is irrelevant if the ultimate access values are ultimately normalized. Parameters ---------- sigma : float This the classical width parameter of the Gaussian / Normal distriution. Returns ------- weight_function : function Function returning weight, for input distance or time, *x*. Examples -------- Import the weights. >>> from access import weights Create a step function with thresholds at 20, 40, and 60. Travel costs are in minutes here, but the code cannot tell if you mix units! >>> fn = weights.gaussian(sigma = 20) >>> {v : fn(v) for v in range(0, 61, 20)} {0: 1.0, 20: 0.6065306597126334, 40: 0.1353352832366127, 60: 0.011108996538242306} Compare this to a simpler formulation: >>> import numpy as np >>> {x : np.exp(-x**2/2) for x in range(4)} {0: 1.0, 1: 0.6065306597126334, 2: 0.1353352832366127, 3: 0.011108996538242306} """ if sigma == 0: raise ValueError("Sigma must be non-zero.") return lambda x: np.exp(-x * x / (2 * sigma**2)) # / np.sqrt(2*np.pi*sigma**2)
[docs]def gravity(scale, alpha, min_dist=0): """ Create a gravity function from a scale :math:`s` and :math:`\\alpha` parameters as well as an optional minimum distance :math:`x_\\text{min}`. The function is of the form :math:`f(x) = (\\text{max}(x, x_\\text{min})/s)^\\alpha`. Note that there is no overall normalization. Parameters ---------- scale : float Scaling value, normalizing the function input. alpha : float Power to which the normalized inputs are raised. Note that it is not implicitly negative (i.e., :math:`x^\\alpha` instead of :math:`1/x^\\alpha`. min_dist : float A 'standard' issue with gravity model is the infinite potential at 0 distance or time. This can be rectified crudely by specifying a minimum distance, and setting any input exceeding that minimum to the minimum itself. The default threshold is 0. Returns ------- weight_function : function Function returning weight, for input distance or time, *x*. Examples -------- Import the weights: >>> from access import weights Create a step function with thresholds at 20, 40, and 60. Travel costs are in minutes here, but the code cannot tell if you mix units! >>> fn = weights.gravity(scale = 20, alpha = -2, min_dist = 1) >>> {t : round(fn(t), 2) for t in [0, 1, 2, 20, 40, 60]} {0: 400.0, 1: 400.0, 2: 100.0, 20: 1.0, 40: 0.25, 60: 0.11} """ return lambda x: np.power(max(x, min_dist) / scale, alpha)