Sampling form non-uniform distributions
If we want to represent regions of our parameter space to different degrees, we can use non-uniform distributions for sampling. In such cases, we can build our sampler by inheriting from SamplerBase and implementing our custom sampling logic there.
Note: this can also introduce bias to the sensitivity of the parameters, thus it should be handled with care.
Example of a custom sampling scenario
This example demonstrates how to sample three parameters: alpha, beta, and gamma. The alpha and beta parameters are uniformly distributed, while gamma follows a standard normal distribution, which is scaled to fit between 0 and 5.
Asssumptions
The sampled parameters are provided in sampling_config if the model evaluation can be handled by EMSA (i.e. we sample “basic” parameters),
or
The SamplerBase.lhs_bounds member variable contains the sampling boundaries in the correct format. (for an example of the 2. option, see ContactSampler or VaccinatedSampler in emsa_examples)
We also assume that gamma was sampled in between 0 and 1. Then the following steps will provide us the desired result:
Steps
Use SamplerBase.get_lhs_table() to generate a Latin Hypercube Sampling (LHS) table with uniformly distributed values for all parameters.
Create a function that converts uniformly distributed values on [0, 1] into normally distributed values on the interval [0, 5].
Apply this function to the gamma values in the LHS table.
Implementation
from scipy.stats import norm
from emsa.sensitivity import SamplerBase
import numpy as np
def uniform_to_normal_on_interval(data, std=1):
# Convert uniform [0, 1] to standard normal using the inverse CDF (Probit function)
normal_values = norm.ppf(data)
# Apply the logistic transformation to map to (0, 5)
transformed_values = 5 / (1 + np.exp(-std * normal_values))
return transformed_values
class CustomSampler(SamplerBase):
def __init__(self, sim_object, variable_params=None):
super().__init__(sim_object, variable_params)
def run(self):
lhs_table = self.get_lhs_table()
# Note: if gamma was age dependent, we can use a slice object to perform the following
gamma_idx = 2
# Apply the sampling transformation
transformed_gamma = uniform_to_normal_on_interval(lhs_table[:, gamma_idx])
# Overwrite old values with the transformed ones
lhs_table[:, gamma_idx] = transformed_gamma
# Calculate targets, etc.
self.get_sim_output(lhs_table)