bayesian_models package

Module contents

Submodules

bayesian_models.core module

class bayesian_models.core.BESTCoreComponent(distributions: dict[str, bayesian_models.core.Distribution] = {}, model: Model | None = None, group_distributions=(), permutations=(), std_difference: bool = False, effect_magnitude: bool = False)

Bases: CoreModelComponent

Core Model Component for the BEST group comparison model

Injecting basic random variables into the model (the distributions argument) is delegated to the parent CoreModelComponent. This component inserts the following deterministics instead:

\[\begin{array}{c} \Delta\mu_{i,j} =\ \mu_i-\mu_j \\ \Delta\sigma_{i, j} = \sigma_i-\sigma_j\\ E = \dfrac{\hat{x_i}-\hat{x_j}}{ \sqrt{ \frac{\sigma_i^2+\sigma_j^2}{2} } } \end{array}\]

By default only the :math:Deltamu quantity is added. Pass std_difference=True to include :math:Deltasigma and effect_size=False to add the effect size to the trace (will also automatically add :math:Deltamu). Used internally only. The BEST class handles the external API.

Example Usage:

core_dists = dict(
                ν = distribution(
                pm.Exponential, "ν_minus_one", 1/29.0, 
                transform = lambda e: e+1.0
                ),
                "obs_0" = distribution(
                    pm.Data, "y0", X0, mutable=False
                    ),
                "obs_1" = distribution(
                    pm.Data, "y1", X1, mutable=False
                    ),
                μ_0 = distribution(
                        pm.Normal, "μ_0", 
                            mu = X0.mean(),   
                            sigma = 2*X0.std(),
                            shape = X0.shape[-1]
                        ),
                σ_0 = distribution(
                    pm.Uniform, 'σ_0', 
                    lower = 1e-1,
                    upper = 10, 
                    shape=X0.shape[-1]),
                μ_1 = distribution(
                        pm.Normal, "μ_1", 
                            mu = X1.mean(),   
                            sigma = 2*X1.std(),
                            shape = X1.shape[-1]
                        ),
                σ_1 = distribution(
                    pm.Uniform, 'σ_1', 
                    lower = 1e-1,
                    upper = 10, 
                    shape=X1.shape[-1])
}
likelihoods = [
        LikelihoodComponent(
            name = "y_obs_0",
            observed = "obs_0",
            distribution = pm.StudentT,
            var_mapping = dict(
                mu = 'μ_,
                sigma = 'σ_1',
                nu = 'ν',
            )
        ),
        LikelihoodComponent(
            name = "y_obs_0",
            observed = "obs_0",
            distribution = pm.StudentT,
            var_mapping = dict(
                mu = 'μ_,
                sigma = 'σ_1',
                nu = 'ν',
            )
        ),
    ]
# Likelihoods passed to the builder instead
BESTCoreComponent(
                distributions = core_dists,
                group_distributions = ...,
                permutations = ..., 
                std_difference = False, 
                effect_magnitude = False,
)

Object Attributes:

  • _group_distributions:tuple := Aggregated groupwise distributions
  • _permutations:tuple := (Technically combinations) all possible unique pairs of levels for the categorical variable defining the groups. Tracks all possible pair-wise comparisons
  • _derived_quantities:dict[str, str]=dict(means=[], stds = [], effect_magnitude = []) := Aggregated deterministics
  • _std_difference:bool=False := If True computes the :math:Deltasigma deterministic and adds it to the trace. Optional. Defaults to False
  • _effect_magnitude:bool=False := If True compute the ‘effect_size’ deterministic quantity. Optional and defaults to False
  • variables:dict[str, Any] := A dictionary mapping internal variable names to a variable references. Added by the CoreModelObject parent class. Enables different components to access variables other than those in their context (i.e. LikelihoodComponent can access the variables to be linked to its shape parameters)
variables: dict
class bayesian_models.core.CoreModelBuilder(*, core_model: ~bayesian_models.core.CoreModelComponent | None = None, likelihoods: list[bayesian_models.core.LikelihoodComponent] | None = None, free_vars: ~bayesian_models.core.FreeVariablesComponent | None = None, adaptor: ~bayesian_models.core.ModelAdaptorComponent | None = None, coords: dict[str, typing.Any] = <factory>, response: ~bayesian_models.core.ResponseFunctionComponent | None = None)

Bases: ModelBuilder

Core model builder object.

Sequentially composes the model object by inserting it’s various components. Every model should supply at least a subclass of CoreModelComponent and a list of Likelihood components. All available components, in order are:

  • core_model:CoreModelComponents := The basic structure of the model, including its equations and basic random variables (REQUIRED)
  • link:LinkFunctionComponent := A link function to be applied to the model. (OPTIONAL)
  • adaptors:ModeAdaptor := An ‘output adaptor’ component that splits the model output tensor into multiple subtensor and inserts them to the computation graph. (OPTIONAL)
  • response:ResponseFunctionComponent := A response function whose model outputs will be passed through. (OPTIONAL)
  • free_vars:FreeVariablesComponent := A additional variables component that inserts variables not explicitly involved in the models’ core equations. (OPTIONAL)
  • likelihoods:Sequence[LikelihoodComponent] := A collection of likelihood components, to be added to the model. (REQUIRED)

Example usage:

from bayesian_models.core import CoreModelBuilder
from bayesian_models.core import LikelihoodComponent
from bayesian_models.core import ResponseFunctionComponent
from bayesian_models.core import FreeVariablesComponent
from bayesian_models.core import ModelAdaptorComponent

# Should be called indirectly via the director
d = CoreModelBuilder(
    core_model = CoreModelComponent(),
    likelihoods=[LikelihoodComponent(), ...], 
    response  = ResponseFunctionComponent(), 
    free_vars = FreeVariablesComponent(),
    adaptor = ModelAdaptorComponent(), 
    )

Object Attributes:

  • core_model:Optional[CoreModelComponent] = None := The core model component. Should subclass CoreModelComponent
  • likelihoods:Optional[list[LikelihoodComponent]] = None := The likelihood component object, defining the likelihood for the model
  • model:Optional[pymc.Model] := The pymc.Model object. Should be created elsewhere and handed to the builder
  • model_variables:dict[str, Any] := A general catalogue of all the models’ variables. Maps variable names to references to the variables, allowing for easy lookup
  • free_vars:Optional[FreeVariablesComponent]=None := The component defining ‘extra’ random variables, i.e. those not directly participating in the models’ equations
  • adaptor:Optional[ModelAdaptorComponent]=None := A model adaptor component which splits the models’ raw output into subtensors
  • response:Optional[ResponseFunctionComponent]=None := The ResponseFunction component, defining functions that transform variables in the model to other variables
  • coords:dict[str,Any] = field(default_factory=dict) := Coordinates for the model object itself. Passed as a dict to the pymc allowing for label coordinates after inference. Collected from the data object itself

Object Methods:

  • __post_init__()->None := Validate that minimal components are present in the model

  • _validate_likelihoods()->None := Validate that all shape parameters of the specified likelihoods are defined in the model stack

    Danger

    At present, little validation is being done, to assume that all of the distributions’ parameters are correctly defined and the domains match. Responsibility for these validations in on the user

  • build()->None := Build the model by sequentially calling separate components to add their variables to the context stack. Will also update the builders’ internal catalogue of all variables present in the model

  • __call__()->None := Build the model updating or create the underlying pymc.Model object

adaptor: ModelAdaptorComponent | None
build() None

Construct the model according to the specified components.

Call specified components, in order, to add the variables of each to the model. Maintains an internal catalogue of variable names mapped to refs to the objects

coords: dict[str, Any]
core_model: CoreModelComponent | None
free_vars: FreeVariablesComponent | None
likelihoods: list[bayesian_models.core.LikelihoodComponent] | None
model: Model | None
model_variables: dict
response: ResponseFunctionComponent | None
class bayesian_models.core.CoreModelComponent(*, distributions: dict[str, bayesian_models.core.Distribution] = <factory>, model: ~pymc.model.Model | None = None)

Bases: object

Core model component.

Inserts basic random variables to the context stack, maintaining an internal catalogue of variables inserted for latter access. Concrete model objects should subclass this component and extend its call method by defining the models’ equations in deterministic nodes. If a concrete model produces some explicit quantity as an output, this should generally be named ‘f’.

Example usage:

core = CoreModelComponent(
            distributions = dict(
                beta0 = distribution(pymc.Normal,
                'beta0', 0,1),
                beta1 = distribution(pymc.Normal,
                'beta1', mu = 0, sigma=1),
            ) # OLS-like example, using convenience
            # method :code:`distribution` to access 
            # the :code:`Distribution` class
    )

Object Attributes:

  • distributions:dict[str, Distribution] := A dictionary mapping random variable names to their priors/ distributions. The Distribution class encapsulates all the information for a prior distribution. Can be accessed via the convenience method distribution
  • variables[str, Any] := A catalogue of basic random variables added to the model. Child classes extend this by adding their deterministics
  • model:Optional[pymc.Model] := A reference to pymc.Model object itself. Is created or defined by the ModelBuildDirector and handed to the builder to construct the model

Object Methods:

  • __call__()->None := Assumes a pymc.Model context stack is open. Adds all specified random variables to the model by calling them from the distributions dict and adds them to the variables catalogue

distributions: dict[str, bayesian_models.core.Distribution]
model: Model | None
variables: dict
class bayesian_models.core.Distribution(*, name: str = '', dist: ~typing.Type[~pymc.distributions.distribution.Distribution] | ~typing.Type[~typing.Callable] = <class 'pymc.distributions.distribution.Distribution'>, dist_args: tuple = (), dist_kwargs: dict = <factory>, dist_transform: ~typing.Callable | None = None)

Bases: object

Data container class for user-specified distributions.

Supply a distribution dist along with any desired arguments dist_args and dist_kwargs. If the distribution needs to be modified, for example by shifting it by some amount, supply a dist_transform:Callable. Optionally a name can be provided. As a data container class, it has no methods.

NOTE: For data nodes, the dist argument should by the function pymc.Data

Example usage:

dist = Distribution(
    dist=pymc.Normal, 
    name='some_name', 
    dist_args=(0,), 
    dist_kwargs=dict(sigma=1) 
)

dist = Distribution(
    dist=pymc.Exponential, 
    name='exp', 
    dist_args=(1/29.0,), 
    dist_transform=lambda d:d+1 
)

dist = Distribution(
    name='inputs', 
    dist=pymc.Data,
    dist_args=(np.random.rand(50,5), ),
    dist_kwargs=dict(mutable=True)
)

Object Attributes:

  • name:str=’’ := A name for the distribution / random variable. Technically optional but should be provided
  • dist := For random variables the distribution to be used as a prior. Initially a reference to the class, will be latter swapped to an instance of the class. For data nodes, the function pymc.Data can be passed instead
  • dist_args:tuple := Positional arguments to the distribution
  • dist_kwargs:dict := Keyword arguments to the distribution
  • dist_transform:Optional[Callable]=None := A Callable that is used to perform a numerical transform to the variable. Will not be explicitly tracked by the model (its result will). Used to offset, and manipulate core distributions. Optional. Defaults to None
dist: Type[Distribution] | Type[Callable]
dist_args: tuple
dist_kwargs: dict
dist_transform: Callable | None
name: str
class bayesian_models.core.FreeVariablesComponent(dists: dict[str, bayesian_models.core.Distribution] = <factory>)

Bases: object

Component representing additional variables to be inserted to the model.

Used for variables not explicitly involved in the core model itself, i.e. the equations describing the model. For example the noise parameter in linear regression:

\[\begin{array}{c} w0 \thicksim \mathcal{N}(0,1)\\ w1 \thicksim \mathcal{N}(0,1)\\ μ = X*w0+w1\\ σ \thicksim \mathcal{N}(0,1)\\ y \thicksim \mathcal{N}(μ, σ)\\ \end{array}\]

The dists argument supplied is a dict of names to Distribution instances, representing the distributions to be inserted to the model.

Example usage:

fvars = FreeVariablesComponent(
        dict( sigma = Distribution(name='sigma',
            dist=pymc.Normal, dist_args=(0,1)
            )
        ) # Insert random variable 'sigma' to the model

Object Attributes:

  • variables:dict := A catalogue of variables inserted into the model. Is a dictionary mapping variable names to references to the appropriate object
  • dists:dict[str, Distribution] := Distributions to be added to the model

Object Methods:

  • __call__()->None := Expects to be executed with a pymc.Model context stack open. Adds all distributions to the model and updates the variables attribute
dists: dict[str, bayesian_models.core.Distribution]
variables: Any
class bayesian_models.core.LikelihoodComponent(*, name: str = 'y_obs', observed: str = 'outputs', distribution: ~typing.Type[~pymc.distributions.distribution.Distribution] = <class 'pymc.distributions.continuous.Normal'>, var_mapping: dict[str, str] = <factory>)

Bases: object

Adds a likelihood component to the model.

var_mapping must be supplied, defining which model variables map to which likelihood shape parameters. For example distribution=pymc.Normal and var_mapping=dict(mu = ‘f’, sigma=’sigma’). The keys of the var_mapping dict are strings which must exactly match the shape parameters of the likelihood. Values should be the internal names of model variables, specified during their creation. name and observed correspond to the name of the likelihood object itself and the name of the observed data node in the model. Should generally be left to their defaults, except when the model has multiple likelihood/observed nodes.

Example usage:

like = LikelihoodComponent(
    name = 'y_obs', # Default likelihood name observed =
    'observed', # Default name for # the name of the input
    data node distribution = pymc.Dirichlet, # Defaults # to
    pymc.Normal var_mapping = dict(
        a = 'f', ) # Mapping of distribution shape
        parameters # to model parameter names. 'f' is
        usually # the default name for the core model #
        output
    )

Object Attributes:

  • name:str=’y_obs’ := The name for the likelihood variable

  • observed:str=’outputs’ := The internal name of the data node containing the observations. Should match the name attribute of the Distribution object that defined the data node
  • distribution:Type[pymc.Distribution]=pymc.Normal := The distribution for the likelihood/observations
  • var_mapping:dict[str, str] := Mapping of the likelihoods’ shape parameters to internal names of model variables to be supplied to the respective parameter. The keys are shape arguments to the supplied distribution. The items are strings representing variable names that will be looked up in the variable catalogue

Object Methods:

  • __call__(observed, var_mappingLdict)->None := Expects to be called with pymc.Model context open and wil add the likelihood to the model. observed is the result of a lookup to the models’ variables catalogue for the observed attribute and is a reference the observations. var_mapping has the same keys as the original and its items are the result of a lookup on the var_mapping item lookup into the models variables catalogue
distribution: Type[Distribution]
name: str
observed: str
var_mapping: dict[str, str]
class bayesian_models.core.LinearRegressionCoreComponent(distributions: dict[str, bayesian_models.core.Distribution] = {}, var_names: dict[str, str] = {}, model: Model | None = None)

Bases: CoreModelComponent

Core model component for linear regression

Specifies the model as

\[f = XW+b\]

Inserts the deterministic variable ‘f’ to the model. Delegates definition of the random variables to the CoreModelComponent parent.

NOTE: When all the priors and the likelihood are Normal this is analytically tractable and MCMC is not needed. Included here as a reference example mostly, though one could run a linear regression with an unusual likelihood / response functions etc

Class Attributes:

  • var_names:dict[str, str] := Alternate names for the various variables of the model. Allows users to refer to the variables by a different name e.g. “b” instead of ‘W’
  • model_vars:set := The models’ variable names

Object Attributes:

  • variables:dict[str, str] : Catalogue mapping variables names to references to the variables. Created by the parent and extended to include the deterministic ‘f’
  • var_names:dict[str, str] := Mapping of internal variable names to user-defined names. Optional. Defaults to an empty dict. Any user supplied variables not corresponding to known model variables are ignored. Any variable aliases not supplied by the user are replaced with their defaults. Warns on any mismatch

Private Attributes:

Variables used internally, mainly for input validation

  • s1:set[str] := User-defined/supplied variable names
  • s2:set[str] := Model variables (class level attribute)

Object Methods:

  • __call__()->None := Add the models’ equation to the model as a deterministic node. Assumes a pymc.Model context stack is open. Model output is named var_names['equation'] ‘f’ by default
distributions: dict[str, bayesian_models.core.Distribution]
model: Model | None
model_vars = {'data', 'equation', 'intercept', 'slope'}
var_names = {'data': 'inputs', 'equation': 'f', 'intercept': 'b', 'slope': 'W'}
variables: dict
class bayesian_models.core.ModelAdaptorComponent(*, record: bool = True, var_mapping: dict[str, typing.Callable] = <factory>)

Bases: object

Adds an ‘output adaptor’ component to the model, which ‘splits’ the models output tensor into other variables.

The splitting logic is specified by the var_mapping argument, which is a dict whose keys are strings representing variable names, and whose items are Callables that accept and return theano tensors. The record boolean argument decides if the result of all “splits” will be wrapped in a deterministic node.

Example usage:

adaptor = ModelAdaptorComponent(
    record = True, # Keep the new variables as 
    # Deterministic nodes for later access
    var_mapping = dict(
        mu = lambda tensor: tensor.T[0,...],
        sigma = lambda tensor: tensor.T[1,...],
    ) # Split model output 'f', a tensor, into two 
    # tensors named 'mu' and 'sigma', wrapped as 
    # deterministics in the model.

Object Attributes:

  • var_mapping:dict[str, Callable] := Mapping of variable names to Callable objects which return the variable. All Callables here receive exactly one argument, the tensor that is the output of the model and the Callable should execute the splitting, returning exactly one subtensor
  • record:bool=True := If True (default) records the subtensors as deterministic variables, adding them to the models posterior trace. Otherwise, they are treated as nuissance intermediates, accessible via the models’ var_names catalogue
  • variables:dict := Catalogue of new objects added to the model by this component. Keys are names, and items are references to the subtensor objects themselves. Allows ‘anonymous’ non-deterministic subtensors to be accessed by other components without being added to the models’ trace

Object Methods:

  • __call__(output)->None := Creates and adds specified subtensors to the model. Assumes a pymc.Model context stack is open. output is a reference to the models output. Also updates the variables attributed with all the subtensors created. output will be passed to all the Callables specified in var_mapping
record: bool
var_mapping: dict[str, Callable]
variables: dict
class bayesian_models.core.ModelBuilder

Bases: ABC

Abstract base class for model builders

abstract property model_variables
class bayesian_models.core.ModelDirector(core_component: CoreModelComponent, likelihood_component: list[bayesian_models.core.LikelihoodComponent], response_component: ResponseFunctionComponent | None = None, free_vars_component: FreeVariablesComponent | None = None, adaptor_component: ModelAdaptorComponent | None = None, coords: dict | None = {})

Bases: object

Model construction object.

Delegates model construction to a specified model builder.

Example usage:

# Will not work with empty objects. All except the first
# two arguments are optional and can be ignored
d = ModelDirector(
    CoreModelComponent(),
    LikelihoodComponent(),
    response_component  = ResponseFunctionComponent(),
    free_vars_component = FreeVariablesComponent(),
    adaptor_component = ModelAdaptorComponent(),
)

Object Attributes:

  • builder:Type[ModelBuilder] := The model builder object. Should be left to the default as only a single Builder is implemented

Object Properties:

  • model:pymc.Model := The underlying pymc.Model object, exposed to the user. Is not an actual object property, but exposes the one of the underlying builder object

Object Methods:

  • __call__()->None := Calls the underlying model builder object to construct the actual model object

builder

alias of CoreModelBuilder

property model: Model | None
class bayesian_models.core.Response(name, func, target, record)

Bases: tuple

Container object for response functions

Response functions are model components that transform model variables into other model variables. This is a collections.namedtuple container and has no methods

Object Attributes:

  • name:str := An internal name for the transformation and its result
  • func:Callable := The Callable object that handles the actual transformation
  • target:str := Internal name for the variable that is to be transformed. The result of a lookup for this variable becomes the input to the Callable in the func field. This should be the only argument to the Callable
  • record:bool := If True the result of the transformation will be wrapped in a deterministic variable and preserved in the posterior trace. Else they will be accessible only internally, via the variables property
func

Alias for field number 1

name

Alias for field number 0

record

Alias for field number 3

target

Alias for field number 2

class bayesian_models.core.ResponseFunctionComponent(responses: ResponseFunctions)

Bases: object

Model component representing Response functions.

Accepts response functions specified via the ResponseFunctions class. Adds them to the model and maintains an internal catalogue for variables added as variables.

Example usage:

res_comp = ResponseFunctionComponent(
    ResponseFunctions(
        functions = dict(
            exp = pymc.math.exp, 
            tanh = pymc.math.tanh
        ),
        records = dict(exp=True, tanh=False),
        application_targets = dict(exp="f", 
        tanh="exp")
    )
)

Object Attributes:

  • responses:ResponseFunctions := A ResponseFunctions object encapsulating all the response functions to be added to the model
  • variables:dict[str, Any] := A catalogue of variables added to the model, stored as mappings of strings (names) to references to the underlying object

Object Methods:

  • __call__(modelvars:dict[str, Any])->None := Add specified response functions to the model. Assumes a pymc.Model context is open. Updates the variables attribute. modelvars is the general catalogue of variables present in the model as name:str to object mappings (supplied by the builder)
responses: ResponseFunctions
variables: dict
class bayesian_models.core.ResponseFunctions(functions: dict[str, typing.Callable] = <factory>, application_targets: dict[str, str] = <factory>, records: dict[str, bool] = <factory>)

Bases: object

Data container for Response functions.

Accepts three mappings as dicts. All three map strings representing variable names for the result of the response to a parameter. The functions argument maps names to the actual functions themselves. The application_targets parameter maps transformed variable names to the variables that are inputs to the transformation. The records parameter maps variable names to a boolean representing whether they should be recorded or not. True will wrap the result of the transform into a deterministic node, False will not. The application_targets and the records parameters can be partially or completely omitted. In this case, record defaults to True and the application_target default to ‘f’ a general name for the raw model output. If any variable is found in either application_targets or records but not in functions an exception is raised, since not reasonable inference can be made for the transform function instead.

Example usage:

# Pass all parameters explicitly (recommended)

ResponseFunctions(
    functions = dict(exp = pymc.math.exp, tanh =
    pymc.math.tanh), records = dict(exp=True, tanh=False),
    application_targets = dict(exp="f", tanh="exp")
) # Partially omit application_targets using defaults 'f'

ResponseFunctions(
    functions = dict(exp = pymc.math.exp, tanh =
    pymc.math.tanh), records = dict(exp=True, tanh=False),
    application_targets = dict(tanh="exp") 
    ) # Pass the
    # desired Callables leaving everything to their
    # defaults. In this case two different response functions
    # are applied to the same input 'f'. Both are recorded
    # with :code:`pymc.Deterministic` the name is the key 
    # provided

ResponseFunctions( functions = dict(exp = pymc.math.exp,
tanh = pymc.math.tanh) )

This object is an Iterable over response functions

Object Attributes:

  • functions:dict[str, Callable] := A dictionary mapping internal variable names to Callable objects defining the transformation
  • records:dict[str, bool] := A dictionary mapping internal variable names to booleans. If the boolean is True the variable is wrapped in a deterministic node and preserved in the posterior trance. Else it accessible only internally. Optional. Anything not explicitly defined here is inferred to be true
  • application_targets:dict[str, str] := A dictionary mapping response names to the internal name of the variable to be transformed. Optional. Any keys missing are automatically mapped to ‘f’, the default name for core model output tensor

Private Attributes:

  • _sf:set[str] := Set of function names specified
  • _st:set[str] := Set of function targets specified (via application_targets keys)
  • _missing_records:set[str] := Set of function records (keys) not explicitly specified by the user
  • _missing_targets:set[str] := Set of function targets (keys of application_targets) not explicitly set by the user
  • _iter:Optional[Iterable] := Iterator object over the specified functions used internally to make the object an iterable
application_targets: dict[str, str]
functions: dict[str, Callable]
get_function(func: str) Response

Returns all data kept on a single response function as a namedtuple for ease of access. Looks up all specs for a response and returns a namedtuple with the results packaged. Fields provided are name, func, target and record

records: dict[str, bool]
bayesian_models.core.distribution(dist: Distribution, name: str, *args, transform: Callable | None = None, **kwargs) Distribution

Convenience method for fresh Distribution instance creation.

Accepts a a distribution and a name, along with optional args and kwargs and returns a Distribution object matching those parameters.

Example usage:

distribution(pymc.Normal, 'W', 0,1)
# Equivalent to Distribution(dist = pymc.Normal, 
# dist_name = 'W', dist_args = (0,1), dist_kwargs=dict()
# )
distribution(pymc.Beta, 'b', alpha=1,beta=1)
# Equivalent to Distribution(dist=pymc.Beta, dist_name='b',
# dist_args=tuple(), dist_kwargs=dict(alpha=1, beta=1))
distribution(pymc.StudentT, 'T', 0, sigma=1, nu=2)
# Equivalent to Distribution(dist=pymc.StudentT, 
# dist_name='b', dist_args=(0,), dist_kwargs=dict(sigma=1,
# nu=2))

bayesian_models.data module

class bayesian_models.data.CommonDataProcessor(*, nan_handler_context: ~bayesian_models.data.NANHandlingContext = NANHandlingContext(_nan_strategy=<class 'bayesian_models.data.ExcludeMissingNAN'>, nan_handler=ExcludeMissingNAN(new_coords=None, new_dims=None, axis=0, constructor=None), kwargs={}), cast: ~numpy.dtype | None = None, type_spec: ~typing.Any | None = None, casting_kwargs: dict = <factory>)

Bases: DataProcessor

Common use-case data pre processor.

Will handle the following data preprocessing tasks:

  • converting the data structure to a common internal interface
  • handling of missing values

  • casting to data type (Optional)

  • validate data types (Incomplete)

Can be subclassed for extended functionality or overriden.

Object Attributes:

  • nan_handler:NANHandlerContext := The missing values handler. Optional. Defaults to ExcludeMissingNAN. Initially a ref to the context class, will be replaced by a instance of that class.
  • cast:Optional[np.dtype]=None := Attempt to forcefully cast all inputs to the specified type. Optional. Defaults to np.float32. Setting this to None will disable typecasting
  • type_spec := Schema to validate. Not implemented and will be ignored
  • casting_kwargs:dict={} := Keyword arguements to be forwarded to the underlying typecaster. See numpy for details. Defaults to an empty dict.

Danger

Typecasting is not fully implemented due to the limitations of numpy arrays (they are homogenuous structures, whereas pandas DataFrames are not). Use this option only to cast the entire structure to a certain dtype

Object Methods:

  • __call__(data:InputData)->CommonDataStructureInterface := Preprocess the data according the set options and return the result.
cast: dtype | None = None
casting_kwargs: dict
nan_handler_context: NANHandlingContext = NANHandlingContext(_nan_strategy=<class 'bayesian_models.data.ExcludeMissingNAN'>, nan_handler=ExcludeMissingNAN(new_coords=None, new_dims=None, axis=0, constructor=None), kwargs={})
type_spec: Any = None
class bayesian_models.data.CommonDataStructureInterface(*, _data_structure: DataStructure | None = None, _implementor: Type[DataStructure] | None = None)

Bases: DataStructureInterface

Core interface for supported data structures. Should be the only interface provided

Object Attributes:

  • implementor:Type[DataStructure] := Class reference to the type of implementor

    Caution

    This attribute is deprecated and scheduled for removal

Object Properties:

  • data_structure:DataStructure := The core data structure implementation
  • rank:int := The structures’ rank (number of axes)

  • shape:tuple[int] := The shape of the structure

  • dims:numpy.ndarray := Labels for the axes of the structure

  • coords:dict[str, numpy.ndarray] := Labels for the coordinates of the structure. Stored as dictionary mapping axes labels to numpy arrays of labels in that axes. Keys should match elements of the dims property
  • values:numpy.ndarray := The underlying numpy array structure. Usefull for unpacking the structure for other software (like pymc)

Object Methods:

Methods exposed by the tensor. Except where methods reduce the entire structure to 0D, all should return another CommonDataStructureInterface permitting method chaining. Whenever a structure would be reduced to 1D, a 2D row-vector structure will be returned instead

  • transpose(axis:Optional[AXES_PERMUTATION] = None) := Return a tranposed version of the object. Signature is the same as numpy and must return the same default. Should always return the same type of object. The T attribute is an alias for this method
  • isna(axis:Optional[int] = None) := Elementwise isnan. Should default to returning the a boolean tensor of the same shape as the original tensor. When axis is provided this is equivalent to an any operation over this axis. The axis is preseved in the return.

    Note

    This does not actually use numpy.isnan internally. It extends its functionaly by allowing nan checks on object type arrays.

    Danger

    Will not work with strings as missing nan values automatically converted into strings

  • any(axis:Optional[int] = None) := When axis=None perform any over the entire array and return a boolean. Otherwise perform the operation over the specified axis, preserving the axis
  • all(axis:Optional[int] = None) := When axis=None perform all over the entire array and return a boolean. Otherwise perform the operation over the specified axis, preserving the axis
  • iterrows() := Iterate over the first axis of the structure Similar to pandas.DataFrame.iterrows()
  • itercolumns() := Iterate over the second axis of the structure. Similar to pandas.DataFrame.itercolumns
  • unique(axis:Optional[int] = None) := Return unique values of the structure. Returns a Generator object that yields length 2 tuples of the general form (Optional[label:str], array). The first element of the tuple is either None or an array of unique elements. When axis is None, (default) the Generator yields only a single element, whose first element is None, and whose other element is an array of all unique values in the array. When axis is provided as an integer, the resulting Generator, loops over the specified axis, yielding tuples of the label in the current iteration (coordinate of the specified axis) and numpy arrays of all unique values in the subtensor (as a vector)
  • __getitem__(obj) := DataStructure indexing. All conventional indexing options are supported, including slicing with labels and mixed label/index based indexing and selecting. The step argument must be an integer (or None) all others can be any mix of label and index based indexers. For example:
    obj[0,0,0] obj[:5:2, "var1",0]
    obj['sample_0':'sample_10':2, 5,...]
    obj['sample_5',...] obj[0:15:"sample",...]
    # Illegal - step must be an integer 
    
  • mean(axis=None, keepdims=True, skipna=True) := Compute the arithmetic mean along the specified axis (or the entire structure if None - default). If keepdims=True the specified dimention is kept in the result with a single coordinate named ‘sum’, making the result correctly broadcastable to the original. Else the dimention is reduced. If skipna=True NaN values are ignored else, all coordinates with at least one NaN will return NaN
  • ops := Basic operators are supported and generally delegated to the underlying library == >= != > < <=
T(axes: list[int] | tuple[int, ...] | None = None) CommonDataStructureInterface
all(axis: int | None = None, **kwargs)
any(axis: int | None = None, **kwargs) CommonDataStructureInterface | bool_
astype(dtype, **kwargs)
coords() dict[str, numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]]
property data_structure: DataStructure
dims() tuple[str, ...]
dtype()
isna()
itercolumns()
iterrows()
mean(axis: int | None = None, skipna: bool = True, keepdims: bool = True) float | CommonDataStructureInterface

Compute the arithmetic mean along the specified axis

Args:

  • axis:Optional[int]=None := The axis along which to compute the mean. If None (default) returns the mean along the entire structure
  • skipna:bool=True := If True (default) NaN values will be ignored, else every coordinate along the specified axis with at least one NaN will return NaN.
  • keepdims:bool=True := If True (default), the axis along which the mean is computed is kept in the result with a single coordinate named ‘sum’, making the result correctly broadcastable agaist the original. Else reduce the dimension in the result. This argument is ignored if axis is None

Returns:

  • mean:float := The mean of the entire structure (if axis=None)
  • means:CommonDataStructureInterface := A new structure of means. If keepdims=False would reduce the structure below 2D, a 2D structure is returned instead (equivalent to keepdims=True)
missing_nan_flag() bool | None
rank() int
shape() tuple[int, ...]
transpose(axes: list[int] | tuple[int, ...] | None = None) CommonDataStructureInterface
unique(axis: int | None = None, **kwargs)
values() ndarray[Any, dtype[ScalarType]]
class bayesian_models.data.Data(nan_handling: str = 'exclude', processor: ~typing.Type[~bayesian_models.data.DataProcessor] = <class 'bayesian_models.data.CommonDataProcessor'>, cast: ~typing.Any = <class 'numpy.float32'>, type_spec: dict = {}, casting_kwargs: dict = {})

Bases: object

Container for model data with optional preprocessing functionality.

Class Attributes:

  • nan_handlers:set[str]=[‘exlude’, ‘impute’, ‘ignore’] := Valid strategies for missing value handling
  • input_types:set[str]=[‘ndarray’, ‘DataFrame’, ‘DataArray’] := Supported input data structures

Object Attributes:

  • nan_handling:str=’exclude’ := The missing data handling strategy. Has to be one of Data.nan_handlers. Optional. Defaults to ‘exclude’ and discards all axis=0 coordinates with missing values (i.e rows).
  • cast:Any := A data type to force-cast the data to. Optional. Defaults to numpy.float32. Set to None to disable casting
  • type_spec:dict={} := Dictionary specification data validation across the second dimention. Keys should be coordinates (labels) along the second axis(=1) and values should be valid numpy dtypes. Currently ignored
  • casting_kwargs:dict={} := Optional keyword arguments to be forwarded to the type caster. Optional. Defaults to an empty dict. See the numpy documentation for further details. Ignored if cast=None
  • processor:Type[DataProcessor]=CommonDataProcessor := The processor to be used for data processing. Optional and defaults to the generic data processor. Can be overriden to customized with a user specified processor that subclasses DataProcessor or CommonDataProcessor
  • process_director:Optional[DataProcessDirector] := The director for data processing. Optional
  • nan_handler:Optional[NANHandler]=None := The class that handles missing values. None only when unset

Object Methods:

input_types: set[str] = {'DataArray', 'DataFrame', 'ndarray'}
nan_handlers: set[str] = {'exclude', 'ignore', 'impute'}
class bayesian_models.data.DataArrayStructure(obj: DataArray, dims: tuple[str, ...] | None = None, coords: dict[str, numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]] | None = None, dtype=None)

Bases: DataStructure, UtilityMixin

Wrapper class around xarray.DataArray implementing the common interface.

Like all implementations this class implements a common, standardized interface for acceptable tensor data structures, as defined by the DataStructure abstract base class.

Class Properties:

  • accepted_inputs:set := Set of input structured that can be converted into xarray.DataArray. Acceptable classes for the obj attribute

Object Properties:

  • obj:xarray.DataArray := The underlying xarray.DataArray object
  • shape:tuple[int,…] := The shape of the object

  • dims:DIMS := Dimensions of the object. A numpy vector of labels of the dimensions / axes of the object. If the object has dimentions these will be used else defaults are generated automatically. The default names are ‘dim_{i}’ where i the integer indexer of the axis
  • coords:COORDS := The coordinates of the object. Is a dictionary of strings, which are axes names (the same as those of dims) mapped to numpy vectors of labels. These are the labels of the ‘steps’ in each axis. If the object has coordinates, these will be used, else defaults are used (as enumerated integers)
  • rank:int := The structures’ rank i.e. the number of axes

  • dtype:np.dtype := The data type of the structure

  • missing_nan_flag:Optional[bool] = None := Flag for existence of missing values. Should be set by the public interface class

Object Methods:

  • isna()->DataArrayStructure := Return a boolean structure, of the same class and shape as the original, whose elements are booleans indicating if the corresponding element is nan or not. Unlike numpy.isnan will work on objects but not strings
  • any(axis:Optional[int]=None)-> Union[bool, DataArrayStructure] := If axis is None reduce via element wise or the entire array. Else reduce over the axis specified
  • all(axis:Optional[int]=None)-> Union[bool, DataArrayStructure] := If axis is None reduce via element wise and the entire array. Else reduce over the axis specified
  • transpose(axis:Optional[tuple[int,…]] )->DataArrayStructure := Return a transposed structure. If axes is None reverses the dimentions. If provided, axis should be a permutation of the objects’ axes (as a tuple), defining the transposition
  • iterrows()->(str, DataArrayStructure) := Returns an iterator over the zeroth axis of the structure. Yields tuples of coordinates to substructures. Loosely equivalent to:
    def iterrows(X:xarray.DataArray):
        for i in range(X.shape[0]):
            yield (X.coords[i], X[i,...])
    
  • itercolumns()->(str, DataArrayStructure) := Returns an iterator over the first axis of the structure. Yields tuples of coordinates to substructures. Loosely equivalent to:
    def iterrows(X:xarray.DataArray):
        for i in range(X.shape[1]):
            yield (X.coords[i], X[:,i,...])
    
  • cast(dtype:numpy.dtype)->DataArrayStructure := Casts the structure to the specified data type. Returns a fresh DataStrcture object
  • unique(axis:Optional[int]=None)->DataArrayStrcture := Return a unique values in the structure. If axis is provided, unique values will over the specified axis are returned. Else unique values over the entire structure are returned. Is a Generator that yields unique values. If axis=None the Generator yields a single tuple of the form (None, vals) where vals is numpy vector of unique elements in the entire structure. If axis is provided, iterates over the specified axis yielding tuples of the form (coordinate_label, vals) where coordinate_label is the label coordinate of the current iteration. vals is a numpy vector of unique values in the resulting sub structure. Loosely equivalent to:
    def unique(struct):
        i=0
        while True:
            try:
                crd = struct.coords[axis][i]
                vals = numpy.unique(struct.transpose(axis)[i,...])
                yield crd, vals
            except KeyError:
                raise StopIteration
    
  • mean(axis:Optional[int]=None)->DataArrayStructure := Return the mean along the specified axis, or over the entire structure (if axis=None)
T(axes: list[int] | tuple[int, ...] | None = None)
accepted_inputs: set = {<class 'pandas.core.frame.DataFrame'>, <class 'pandas.core.series.Series'>, <class 'xarray.core.dataarray.DataArray'>, <class 'numpy.ndarray'>}
all(axis: int | None = None, **kwargs) bool | DataArrayStructure
any(axis: int | None = None, **kwargs)
cast(dtype, **kwargs)
isna()
itercolumns()
iterrows()
mean(axis: int | None = None, keepdims: bool = True, skipna: bool = True)
transpose(axes: list[int] | tuple[int, ...] | None = None)
unique(axis: int | None = None)

Return unique values of the NDArrayStructure as Generator of length 2 tuples.

When axis is None, the generator yields a single tuple of (None, vals) where vals are all the unique values in the array. When axis is specified, the Generator iterates over the specified axis yielding tuples of (label, unique_values)

class bayesian_models.data.DataFrameStructure(obj: DataFrame, dims: tuple[str, ...] | None = None, coords: dict[str, numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]] | None = None, dtype=None)

Bases: DataStructure, UtilityMixin

Wrapper class around pandas.DataFrame implementing the common interface.

Like all implementations this class implements a common, standardized interface for acceptable tensor data structures, as defined by the DataStructure abstract base class.

Class Attributes:

  • accepted_inputs:set := Valid inputs the constructor. Structures which can be converted are Series, DataFrames and numpy ndarrays

Object Properties:

  • obj:pandas.DataFrame := The underlying pandas.DataFrame object
  • shape:tuple[int,…] := The shape of the object

  • dims:DIMS := Dimensions of the object. A numpy vector of labels of the dimensions / axes of the object.The default names are ‘dim_{i}’ where i the integer indexer of the axis
  • coords:COORDS := The coordinates of the object. Is a dictionary of strings, which are axes names (the same as those of dims) mapped to numpy vectors of labels. These are the labels of the ‘steps’ in each axis. If the object has index and columns, these will be used, else defaults are used (as enumerated integers)
  • rank:int := The structures’ rank i.e. the number of axes
  • dtype:np.dtype := The data type of the structure

  • missing_nan_flag:Optional[bool] = None := Flag for existence of missing values. Should be set by the public interface class

Object Methods:

  • isna()->DataFrameStructure := Return a boolean structure, of the same class and shape as the original, whose elements are booleans indicating if the corresponding element is nan or not.
  • any(axis:Optional[int]=None)-> Union[bool, DataFrameStructure] := If axis is None reduce the entire array via element wise or . Else reduce over the axis specified
  • all(axis:Optional[int]=None)-> Union[bool, DataFrameStructure] := If axis is None reduce the entire array via element wise and. Else reduce over the axis specified
  • transpose(axis:Optional[tuple[int,…]] )->DataFrameStructure := Return a transposed structure. If axis is None reverses the dimensions. If provided, axis should be a permutation of the objects’ axes (as a tuple), defining the transposition
  • iterrows()->(str, DataFrameStructure) := Returns an iterator over the zeroth axis of the structure. Yields tuples of coordinates to substructures. Loosely equivalent to:
    def iterrows(X:pandas.DataFrame):
        for i in range(X.shape[0]):
            yield (X.index[i], X.iloc[i,...])
    
  • itercolumns()->(str, DataFrameStructure) := Returns an iterator over the first axis of the structure. Yields tuples of coordinates to substructures. Loosely equivalent to:
    def iterrows(X:pandas.DataFrame):
        for i in range(X.shape[1]):
            yield (X.columns[i], X.iloc[:,i,...])
    
  • cast(dtype:numpy.dtype)->DataArrayStructure := Casts the structure to the specified data type. Returns a fresh DataStrcture object
  • unique(axis:Optional[int]=None)->DataFrameStructure := Return a unique values in the structure. If axis is provided, unique values will over the specified axis are returned. Else unique values over the entire structure are returned. Is a Generator that yields unique values. If axis=None the Generator yields a single tuple of the form (None, vals) where vals is numpy vector of unique elements in the entire structure. If axis is provided, iterates over the specified axis yielding tuples of the form (coordinate_label, vals) where coordinate_label is the label coordinate of the current iteration. vals is a numpy vector of unique values in the resulting sub structure. Loosely equivalent to:
    def unique(struct):
        i=0
        while True:
            try:
                crd = struct.coords[axis][i]
                vals = numpy.unique(struct.transpose(axis)[i,...])
                yield crd, vals
            except KeyError:
                raise StopIteration
    
  • mean(axis:Optional[int]=None)->DataFrameStructure := Return the mean along the specified axis, or over the entire structure (if axis=None)
T(axes: list[int] | tuple[int, ...] | None = None)
accepted_inputs: set = [<class 'pandas.core.frame.DataFrame'>, <class 'pandas.core.series.Series'>, <class 'numpy.ndarray'>]
all(axis: int | None = None, **kwargs)
any(axis: int | None = None, **kwargs)
cast(dtype, **kwargs)
isna()
itercolumns()
iterrows()
mean(axis: int | None = None, keepdims: bool = True, skipna: bool = True)

Compute the arithmetic mean along the specified axis

Args:

  • axis:Optional[int]=None := The axis to compute the mean over. If None (default), computes the mean over the entire DataFrame. Values are 0 (mean over the rows), 1 (mean over the columns) and None (mean of the entire array)
  • skipna:bool=True := If True ignores NaN values in the dataframe. Else returns NaN for coordinates with at least one NaN
  • keepdims:bool=True := If True the axis over which the mean is computed, is kept in the result with a single coordinate named ‘sum’ (default), making the result correctly broadcastable against the original. Otherwise, the result axis is reduced. Since ArrayStructure object cannot be reduced past 2D the arguement if effectively ignored and always True for DataFrames

Returns:

  • mean:float := The mean of the entire dataframe (axis=None)
  • means:DataFrameStructure := A DataFrame with a single row of means along the specified axis

Raises:

  • ValueError := If axis is not None, 1 or 0

transpose(axes: list[int] | tuple[int, ...] | None = None)
unique(axis: int | None = None)
class bayesian_models.data.DataProcessingDirector(*, processor: ~typing.Type[~bayesian_models.data.DataProcessor] | ~bayesian_models.data.DataProcessor = <class 'bayesian_models.data.CommonDataProcessor'>, nan_handler_context: ~bayesian_models.data.NANHandlingContext = NANHandlingContext(_nan_strategy=<class 'bayesian_models.data.ExcludeMissingNAN'>, nan_handler=ExcludeMissingNAN(new_coords=None, new_dims=None, axis=0, constructor=None), kwargs={}), processor_kwargs: dict = <factory>)

Bases: object

Master composite for data pre processing

Object Attributes:

  • processor:CommonDataProcessor := A reference to the class that represents the data processor. Converted to an instance on said class. Optional. Defaults to CommonDataProcessor
  • nan_handler_context:NANHanderContext := The missing nan handler
  • processor_kwargs:dict = Keyword arguments to be forwarded to the processor instance

Object Methods:

  • __call__(data:InputeData)->CommonDataStructureInterface := Call the processor and return the pre processed data
nan_handler_context: NANHandlingContext = NANHandlingContext(_nan_strategy=<class 'bayesian_models.data.ExcludeMissingNAN'>, nan_handler=ExcludeMissingNAN(new_coords=None, new_dims=None, axis=0, constructor=None), kwargs={})
processor

alias of CommonDataProcessor

processor_kwargs: dict
class bayesian_models.data.DataProcessor

Bases: ABC

Abstract base class for Data Processors

class bayesian_models.data.DataStructure

Bases: ABC

Abstract Base Class for Data Structure implementations

Object Properties:

Common properties exposed by the underlying object

  • obj:DataStructure := The wrapped, underlying object
  • shape:SHAPE := The shape property of the wrapped object
  • dims:DIMS := Labels for the dimensions of the object - the axes
  • coords:COORDS := Labels for each element in each axis i.e distinct row labels, column labels etc
  • rank:int := The tensors rank

  • dtype := The datatype for the elements. For consistency all DataStructure are coerced into homogenous types

Object Methods:

Methods exposed by the tensor

  • transpose(axis:Optional[AXES_PERMUTATION] = None) := Return a transposed version of the object. Signature is the same as numpy and must return the same default. Should always return the same type of object. The T attribute is an alias for this method
  • isna(axis:Optional[int] = None) := Elementwise isnan. Should default to returning the a boolean tensor of the same shape as the original tensor. When axis is provided should this is equivalent to an any operation over this axis. The axis should be preserved in the return
  • any(axis:Optional[int] = None) := When axis=None perform any over the entire array and return a boolean. Otherwise perform the operation over the specified axis, preserving the axis
  • all(axis:Optional[int] = None) := When axis=None perform all over the entire array and return a boolean. Otherwise perform the operation over the specified axis, preserving the axis
  • iterrows() := Iterate over the first axis of the structure. Similar to pandas.DataFrame.iterrows()
  • itercolumns() := Iterate over the second axis of the structure. Similar to pandas.DataFrame.itercolumns
  • cast(dtype, **kwargs) := Attempt to cast tensor elements to dtype. All kwargs are forwarded to numpy. Returns a new copy of the tensor (as a DataStructure object) with the update data type
  • __getitem__(self, obj) := Slice the object in any number of ways. Integer and label based, slices should be acceptable along with arbitrary combinations thereof. Acceptable slice inputs should be: int, str, slice, Ellipsis, list[int,str], tuple[int,str] and all combinations of these. Slice should accept label based specs or integers based ones, or mixes of the two. The step argument only accept integers and raise otherwise. All of the following should be valid:
    obj[5,6] obj["sample_0", 7] obj["sample_7":10:1, ...]
    obj[[6,9], "var1":10:2,...]
    

    If the object would be reduced below a 2d structure, it should padded into 2D as a row-vector

  • unique(axis=None) := Return a the unique values of the data structure as a generator of length 2 tuples. When axis is specified as an integer, the generator iterates over the specified axis, yielding tuples of the label and the unique values of the subtensor. When axis is None (default) return a single element Generator which yields exactly one tuple of (None, UNIQUES), where UNIQUES is a vector of all the unique values in the structure
  • mean(axis:Optional[int] = None, keepdims:bool=True, skipna:bool=True) := Compute the mean along the specified axis. If axis is None the mean will be computed over the entire structure and a numeric is returned. Otherwise a data structure of the same type as the original is returned. If axis is not None, the mean is computed over the specified axis. If keepdims=True (default) the axis is reduced and removed. If keepdims=True then the axis is maintained (and the result is broadcastable to the original) with a single coordinate named “sum”. If skipna=True any invalid elements will be ignored (default) otherwise nan is returned where mean would otherwise be.
  • ops := Elementwise comparison operations such as ‘>’, ‘>=’, ‘==’, ‘<=’, ‘<’ and ‘neq’ are included in the interface but generally delegated to the underlying library
abstract T(axes: list[int] | tuple[int, ...] | None = None)
abstract all(axis: int | None = None) bool | DataStructure
abstract any(axis: int | None = None) bool | DataStructure
abstract cast(typ_spec) DataStructure
property coords: dict[str, numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]]
property dims: tuple[str, ...]
property dtype: Any
abstract isna() DataStructure
abstract itercolumns() DataStructure
abstract iterrows() DataStructure
abstract mean(axis: int | None = None, keepdims: bool = True, skipna: bool = True)
property missing_nan_flag: bool | None
property obj: DataStructure
property rank: int
property shape: tuple[int, ...]
abstract transpose(axes: list[int] | tuple[int, ...] | None = None) DataStructure
property values: ndarray[Any, dtype[ScalarType]]
class bayesian_models.data.DataStructureInterface

Bases: ABC

Abstract Base Class for the external interface (The bridge Abstraction)

Object Properties:

  • data_structure:DataStructure := The core data structure implementation

Object Methods:

Methods exposed by the tensor

  • transpose(axis:Optional[AXES_PERMUTATION] = None) := Return a tranposed version of the object. Signature is the same as numpy and must return the same default. Should always return the same type of object. The T attribute is an alias for this methods
  • isna(axis:Optional[int] = None) := Elementwise isnan. Should default to returning the a boolean tensor of the same shape as the original tensor. When axis is provided should this is equivalent to an any operation over this axis. The axis should be preseved in the return
  • any(axis:Optional[int] = None) := When axis=None perform any over the entire array and return a boolean. Otherwise perform the operation over the specified axis, preserving the axis
  • all(axis:Optional[int] = None) := When axis=None perform all over the entire array and return a boolean. Otherwise perform the operation over the specified axis, preserving the axis
  • iterrows() := Iterate over the first axis of the structure. Similar to pandas.DataFrame.iterrows()
  • itercolumns() := Iterate over the second axis of the structure. Similar to pandas.DataFrame.itercolumns
  • __gettitem__(indexer) := Return the values specified by the indexer. Mix and matching label and integer based indexing is supported. If a slice is provided, the start and stop arguments can be labels, but the step argument must be an integer
  • unique(axis=None) := Return all the unique values in the tensor as a Generator that yields length 2 tuples. If axis is None the Generator yields a single tuple of the form (None, values), where values is a vector of unique values. If axis is provided, the generator iterates over the specified dimention, yielding tuples of the form (label, values) where values is a vector of unique values for the flattened subtensor.
  • mean(axis=None, keepdims=True, skipna=True) := Compute the arithmetic mean along the specified axis (or the entire structure if None - default). If keepdims=True the specified dimention is kept in the result with a single coordinate named ‘sum’, making the result correctly broadcastable to the original. Else the dimention is reduced. If skipna=True NaN values are ignored else, all coordinates with at least one NaN will return NaN
  • ops := Elementwise operations ‘>’, ‘<’, ‘>=’, ‘<=’, ‘==’, ‘!=’ are delegated to the underlying library but a wrapped object is returned for ‘pointwise’ operations, i.e. obj==5, otherwise a boolean is returned
abstract all() DataStructureInterface | bool | bool_
abstract any() DataStructureInterface | bool | bool_
abstract astype(dtype, kwargs) DataStructureInterface
abstract coords() dict[str, numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]]
abstract property data_structure: DataStructure
abstract dims() tuple[str, ...]
abstract dtype() Any
abstract isna() DataStructureInterface | bool | bool_
abstract itercolumns() DataStructureInterface
abstract iterrows() DataStructureInterface
abstract mean(axis: int | None = None, keepdims: bool = True, skipna: bool = False) None
abstract rank() int
abstract shape() tuple[int, ...]
abstract transpose() DataStructureInterface
abstract values() ndarray
class bayesian_models.data.ExcludeMissingNAN(new_coords: dict[str, numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]] | None = None, new_dims: tuple[str, ...] | None = None, axis: int = 0, constructor: DataStructure | None = None)

Bases: NANHandler

Exclude missing values

Common use-case for missing value handling. Discards all coordinates on the first dimention (i.e. rows) along which there are any missing values - updating the objects’ metadata

Object Attributes:

  • new_coords:Optional[COORDS]=None := Updated object coordinates
  • new_dims:Optional[DIMS]=None := Updated object dimentions
  • axis:int=0 := The dimention along which to exclude. Optional. Defaults to 0 (‘rows’). Currently no other options are implemeted and other values are ignored.
  • constructor:Optional[DataStructure]=None := The DataStructure of the object to convert after processing

Object Methods:

axis: int = 0
constructor: DataStructure | None = None
new_coords: dict[str, numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]] | None = None
new_dims: tuple[str, ...] | None = None
class bayesian_models.data.IgnoreMissingNAN

Bases: NANHandler

Identity strategy for nan handling the does nothing.

Only included for completeness’ sake. Returns the object unmodified

Object Methods:

:= Returns the data unchanged

class bayesian_models.data.ImputeMissingNAN

Bases: NANHandler

Imputation missing data handler

Performs imputation, replacing missing nan values with dummy ones that do not distort the underlying distribution. NotImplemented and will raise

class bayesian_models.data.NANHandler

Bases: ABC

Abstract Base Class for missing value handlers

class bayesian_models.data.NANHandlingContext(*, _nan_strategy: ~typing.Type[~bayesian_models.data.NANHandler] = <class 'bayesian_models.data.ExcludeMissingNAN'>, nan_handler: ~bayesian_models.data.NANHandler | None = None, kwargs: dict = <factory>)

Bases: object

Composite for missing values handling. Defines the external interface

Object Properties:

  • nan_handler:NANHandler := The nan handling strategy to apply

Object Methods:

kwargs: dict
nan_handler: NANHandler | None = None
class bayesian_models.data.NDArrayStructure(obj: ndarray[Any, dtype[ScalarType]] | DataStructure, dims: tuple[str, ...] | None = None, coords: dict[str, numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]] | None = None, dtype: Any | None = None)

Bases: DataStructure, UtilityMixin

Wrapper class around numpy arrays implementing the common interface.

Like all implementations this class implements a common, standardized interface for acceptable tensor data structures, as defined by the DataStructure abstract base class

Object Properties:

  • obj:numpy.typing.NDArray := The underlying numpy.ndarray object
  • shape:tuple[int,…] := The shape of the object

  • dims:DIMS := Dimensions of the object. A numpy vector of labels of the dimensions / axes of the object. For numpy arrays defaults are typically used (since numpy arrays have no labels). The default names are ‘dim_{i}’ where i the integer indexer of the axis
  • coords:COORDS := The coordinates of the object. Is a dictionary of strings, which are axes names (the same as those of dims) mapped to numpy vectors of labels. These are the labels of the ‘steps’ in each axis
  • rank:int := The structures’ rank i.e. the number of axes

  • dtype:np.dtype := The data type of the structure

  • missing_nan_flag:Optional[bool] = None := Flag for the existence of missing values. Should be set by the public interface class

Object Methods:

  • isna()->NDArrayStructure := Return a boolean structure, of the same class and shape as the original, whose elements are booleans indicating if the corresponding element is nan or not. Unlike numpy.isnan will work on objects but not strings
  • any(axis:Optional[int]=None)-> Union[bool, NDArrayStructure] := If axis is None reduce via element wise or the entire array. Else reduce over the axis specified
  • all(axis:Optional[int]=None)-> Union[bool, NDArrayStructure] := If axis is None reduce via element wise and the entire array. Else reduce over the axis specified
  • transpose(axis:Optional[tuple[int,…]] )->NDArrayStructure := Return a transposed structure. If axes is None reverses the dimensions. If provided, axis should be a permutation of the objects’ axes (as a tuple), defining the transposition
  • iterrows()->(str, NDArrayStructure) := Returns an iterator over the zeroth axis of the structure. Yields tuples of coordinates to substructures. Loosely equivalent to:
    def iterrows(X:NDArrayStructure):
        for i in range(X.shape[0]):
            yield (X.coords[i], X[i,...])
    
  • itercolumns()->(str, NDArrayStructure) := Returns an iterator over the first axis of the structure. Yields tuples of coordinates to substructures. Loosely equivalent to:
    def iterrows(X:NDArrayStructure):
        for i in range(X.shape[1]):
            yield (X.coords[i], X[:,i,...])
    
  • cast(dtype:numpy.dtype)->NDArrayStructure := Casts the structure to the specified data type. Returns a fresh DataStrcture object
  • unique(axis:Optional[int]=None)->NDArrayStructure := Return unique values in the structure. If axis is provided, unique values over the specified axis are returned. Else unique values over the entire structure are returned. Is a Generator that yields unique values. If axis=None the Generator yields a single tuple of the form (None, vals) where vals is numpy vector of unique elements in the entire structure. If axis is provided, iterates over the specified axis yielding tuples of the form (coordinate_label, vals) where coordinate_label is the label coordinate of the current iteration. vals is a numpy vector of unique values in the resulting sub structure. Loosely equivalent to:
    def unique(struct):
        i=0
        while True:
            try:
                crd = struct.coords[axis][i]
                vals = numpy.unique(struct.transpose(axis)[i,...])
                yield crd, vals
            except KeyError:
                raise StopIteration
    
  • mean(axis:Optional[int]=None)->Union[ float, NDArrayStructure] := Return the mean along the specified axis, or over the entire structure (if axis=None)
T(axes: list[int] | tuple[int, ...] | None = None) NDArrayStructure

Transpose the tensor structure

If axes is not provided, reverse the order of the axes. If provided it should be a valid permutation of the structures’ axes, defining how the transposition should be performed

Example usage

import numpy as np
from bayesian_models.data import NDArrayStructure

struct = NDArrayStructure(np.random.rand(20,5,3))
print(struct.tranpose().shape)
# Output
# (3,5,20) By default, reverse the order of the axes
print(struct.tranpose().shape)
# Output
# (3,5,20) By default, reverse the order of the axes
print(struct.tranpose((1,0,2)).shape) # Reverse the
# first two axes
# Output
# (5,20,3)
# Axes permutations must be explicit
struct.tranpose((1,0, ...)
# TypeError: 'ellipsis' object cannot be interpreted as
# an integer

Args:

  • axes:Optional[AXIS_PERMUTATION]=None := Define how the transposition operation should be performed. If None (default) reverse the order of the axes. If provided, it should be a valid permutation of the structures’ axes, defining the transposition

Returns:

  • nobj:NDArrayStructure := The transposed object
all(axis: int | None = None, **kwargs)

Elementwise and across the structure.

If axis=None return a single boolean across the entire structure equivalent to and across the entire structure. If axis is provided, operate across the axis, reducing it.

Example usage:

import numpy as np
from bayesian_models.data import NDArrayStructure

struct = NDArrayStructure(
    np.random.randint(0,2, size=(10,3), dtype=bool)
    )
print(struct.values)
# Output
# array([[False, False,  True],
#        [False, False,  True],
#        [ True, False,  True],
#        [False,  True,  True],
#        [False,  True,  True],
#        [ True, False, False],
#        [False, False, False],
#        [ True,  True, False],
#        [ True, False,  True],
#        [ True,  True, False]])
print(struct.any(axis=1).values)
# Output:
# array([False, False, False, False,  True, False,
# False, False,  True, False])

Args:

  • axis:Optional[int]=None := The axis across which to operate. If None operate across the entire structure

Returns:

  • any:bool := If axis=None a single boolean across the entire structure
  • anys:NDArrayStructure := If axis is an integer, return a structure with the axis reduced, operating along the axis
any(axis: int | None = None, **kwargs)

Elementwise “or” across the structure.

If axis=None return a single boolean across the entire structure equivalent to or across the entire structure. If axis is provided reduce the axis equivalent to elementwise or across the axis

Example usage:

import numpy as np
from bayesian_models.data import NDArrayStructure

struct = NDArrayStructure(
    np.random.randint(0,2, size=(10,3), dtype=bool)
    )
print(struct.values)
# Output
# array([[False, False,  True],
#        [False, False,  True],
#        [ True, False,  True],
#        [False,  True,  True],
#        [False,  True,  True],
#        [ True, False, False],
#        [False, False, False],
#        [ True,  True, False],
#        [ True, False,  True],
#        [ True,  True, False]])
print(struct.any(axis=1).values)
# Output:
# array([ True,  True,  True,  True,  True,  True,
# True,  True,  True, True])

Args:

  • axis:Optional[int]=None := The axis across which to operate. If None operate across the entire structure

Returns:

  • any:bool := If axis=None a single boolean across the entire structure
  • anys:NDArrayStructure := If axis is an integer, return a structure with the axis reduced, operating along the axis
cast(dtype: dtype, **kwargs)

Change the data type of the structure

Example usage:

import numpy as np
from bayesian_models.data import NDArrayStructure

obj = NDArrayStructure(
    np.random.rand(20,3)
)
# Change the data type to 32-bit floats
obj.cast(np.float32)

Args:

  • dtype:numpy.dtype := The dtype to convert the structure to
  • **kwargs:dict[str, Any] := Keyword arguements to be forwarded to .astype. See the numpy docs for more information

Returns:

  • nstruct:NDArrayStructure := The structure converted to the specified dtype
isna()

Check if the structure has missing or nan values

This implementation works with object dtypes but not strings. Returns a structure of booleans showing if the respective element is nan or not

Example usage:

import numpy as np
from bayesian_models.data import NDArrayStructure

X = np.random.rand(10,3)
X[0,0] = np.nan
obj = NDArrayStructure(X)
print(obj.isna().values)
# Output
#[[ True False False]
# [False False False]
# [False False False]
# [False False False]
# [False False False]
# [False False False]
# [False False False]
# [False False False]
# [False False False]
# [False False False]]
# Returns an NDArrayStructure so methods can be chain
# called
print(obj.isna().any())
# Output:
# True
itercolumns()

Iterate over the zeroth dimension of the structure

Is a Generator that yields coordinates of the first axis as a tuple (coordinate:str, substructure). Coordinate is label of the coordinate of the current iteration. substructure are the unique values of the iteration, loosely equivalent to X[:,i,...].

Example usage:

import numpy as np
from bayesian_models.data import NDArrayStructure

for step in struct.itercolumns():
    print(f"{struct[0]}th iteration")
    print(struct[1].values)
# Output
# 0 iteration
# [[0.87129834 0.52058713 0.3262019  0.77032967
#   0.12151855 0.04655757, ... 0.58081613]]
# ... 
# 4 iteration
# [[0.24766219 0.87327094 0.20295554 0.57563816 0.776743
# ... 0.15798941]]
iterrows()

Iterate over the zeroth dimension of the structure

Is a Generator that yields coordinates of the zeroth axis as a tuple (coordinate:str, substructure). Coordinate is label of the coordinate of the current iteration. substructure are the values of the iteration, loosely equivalent to X[i,...].

Example usage:

import numpy as np
from bayesian_models.data import NDArrayStructure

for step in struct.iterrows():
    print(f"{struct[0]}th iteration")
    print(struct[1].values)

# Output
# 0th iteration
# [[0.87129834 0.28525984 0.8024876  0.22648149
#   0.24766219]]
# 1th iteration
# [[0.52058713 0.64226276 0.54973852 0.02149187
#  0.87327094]]
# ...
# 28th iteration
# [[0.09227537 0.72935584 0.36943861 0.72009057
#  0.83315441]]
# 29th iteration
# [[0.58081613 0.51312354 0.9158358  0.93393108
# 0.15798941]]
mean(axis: int | None = None, keepdims: bool = True, skipna: bool = True)

Compute the arithmetic mean along the specified axis.

Example usage:

import numpy as np
from bayesian_models.data import NDArrayStructure

struct = NDArrayStructure(np.random.rand(10,3))
# Mean of the entire structure
print(struct.mean().values)
# Output
# 0.4621622294767996
# Mean over some columns
print(struct.mean(axis=1).values)
# Output
# array([[0.54527681],
#        [0.35284086],
#        [0.25491467],
#        [0.41629867],
#        [0.47454723],
#        [0.5965149 ],
#        [0.73069869],
#        [0.42783913],
#        [0.21808277],
#        [0.60460858]])
print(struct.mean(axis=1).coords)
# Output
# {'dim_0': array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
# 'dim_1': #array(['sum'], dtype='<U3')}


print(struct1.mean(axis=1, keepdims=False).coords)
# Output
# {'dim_0': array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
# 'dim_1': #array(['sum'], dtype='<U3')}
# DataStructure objects cannot fall below 2D

# For higher dimentional tensors :code:`keepdims=False` will
# reduce the axis
struct1 = NDArrayStructure(np.random.rand(10,3,2))
print(struct1.mean(axis=1, keepdims=False).coords)
# Output
# {'dim_0': array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
# 'dim_2': array([0, 1])}

Args:

  • axis:Optional[int]=None : = When axis=None return the scalar mean of the entire structure (default). Otherwise computes the mean along the specified axis.
  • keepdims:bool=True := If keepdims=True the dimention is maintained in the resulting structure with a single coordinate named ‘sum’ (default). Otherwise, the dimention is reduced and removed from the resulting structure.
  • skipna:bool=True := If skipna=True NaN values will be ignored in the result, otherwise NaN is returned for coordinates with at least one NaN

Returns:

  • nstruct:NDArray := Returns a new NDArrayStructure of means
  • mean:float := If axis=None the mean of the entire structure
transpose(axes: list[int] | tuple[int, ...] | None = None) NDArrayStructure

Transpose the tensor structure

If axes is not provided, reverse the order of the axes. If provided it should be a valid permutation of the structures’ axes, defining how the transposition should be performed

Example usage

import numpy as np
from bayesian_models.data import NDArrayStructure

struct = NDArrayStructure(np.random.rand(20,5,3))
print(struct.tranpose().shape)
# Output
# (3,5,20) By default, reverse the order of the axes
print(struct.tranpose().shape)
# Output
# (3,5,20) By default, reverse the order of the axes
print(struct.tranpose((1,0,2)).shape) # Reverse the
# first two axes
# Output
# (5,20,3)
# Axes permutations must be explicit
struct.tranpose((1,0, ...)
# TypeError: 'ellipsis' object cannot be interpreted as
# an integer

Args:

  • axes:Optional[AXIS_PERMUTATION]=None := Define how the transposition operation should be performed. If None (default) reverse the order of the axes. If provided, it should be a valid permutation of the structures’ axes, defining the transposition

Returns:

  • nobj:NDArrayStructure := The transposed object
unique(axis: int | None = None) tuple[typing.Optional[numpy.ndarray[str]], numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]]

Return the unique elements in the structure.

Return unique values of the NDArrayStructure as Generator of length 2 tuples. When axis is None, the generator yields a single tuple of (None, vals) where vals are all the unique values in the array. When axis is specified, the Generator iterates over the specified axis, yielding tuples of label, unique_values.

Example usage:

import numpy as np
from bayesian_models.data import NDArrayStructure

struct = NDArrayStructure(
    np.random.randint(
        0, 4, size=(10,3)
    )
)
items:tuple[None, np.ndarray] = next(struct.unique()) # Unique # items in the entire structure

# Unique items across an axis
for coordinate in struct.unique(axis=1):
    print(
        "Found these unique items {items} in this coordinate {crd}".format(crd= coordinate[0], items=coordinate[1])
    )

# Output
# Found these unique items [0 1 3] in this coordinate 0
# Found these unique items [0 1 2 3] in this coordinate
# 1
# Found these unique items [0 1 2 3] in this
# coordinate 2

Args:

  • axis:Optional[int]=None := The axis along which to return unique values. If None, return unique elements along the entire structure

Yields:

  • unique:tuple[None, np.ndarray] := If axis=None yield a single typle of (None, val_array), where val_array a numpy vector of all unique elements in the structure
  • unique:tuple[np.ndarray[str], np.ndarray] := If axis is provided yield tuples of (coordinate, values). coordinate is the current value of the coordinate. values is a numpy vector of unique values along the coordinate
property values: ndarray[Any, dtype[ScalarType]]

Return the underlying structure as a numpy.ndarray

Example usage:

import numpy as np
from bayesian_models.data import NDArrayStructure

A = np.random.rand(10,3)
print(A)
# Output
# array([[0.92696729, 0.85774767, 0.74036172],
#       [0.04296317, 0.65726312, 0.97758067],
#       [0.56289662, 0.28891003, 0.62563431],
#       [0.55779293, 0.8921344 , 0.07295159],
#       [0.63069955, 0.48854109, 0.5674133 ],
#       [0.41642828, 0.45982703, 0.22005397],
#       [0.75317745, 0.11725162, 0.46697631],
#       [0.48607453, 0.30890712, 0.41480661],
#       [0.06220708, 0.3917841 , 0.66493793],
#       [0.23265062, 0.28742938, 0.06959736]])
obj = NDArrayStructure(A)
print(obj.values)
# array([[0.92696729, 0.85774767, 0.74036172],
#       [0.04296317, 0.65726312, 0.97758067],
#       [0.56289662, 0.28891003, 0.62563431],
#       [0.55779293, 0.8921344 , 0.07295159],
#       [0.63069955, 0.48854109, 0.5674133 ],
#       [0.41642828, 0.45982703, 0.22005397],
#       [0.75317745, 0.11725162, 0.46697631],
#       [0.48607453, 0.30890712, 0.41480661],
#       [0.06220708, 0.3917841 , 0.66493793],
#       [0.23265062, 0.28742938, 0.06959736]])
class bayesian_models.data.UtilityMixin

Bases: object

Convenience mixin class to to disseminate common functionality. Used for inheritance only

Object Methods:

  • _cut_dims_(axis:Optional[int]=None)->tuple[DIMS, COORDS] := In cases where an axis is reduced (eliminated) in the result, this returns the updated dims and coords as a tuple
  • _dimshuffle_(axes_permutation:AXES_PERMUTATION)->tuple := Given an axes permutation (for transposing structures) permute the dims an coords and return them as tuple

bayesian_models.math module

bayesian_models.math.ELU(x, alpha: float = 1.0)

pytensor implementation of the ELU activation function:

\[f(x) \triangleq \begin{cases} x & x \gt 0 \\ \alpha (e^x-1) &\text{if } b \\ \end{cases}\]

Args:

  • x := The input tensor

  • alpha:float=1.0 := The \(\alpha\) parameter of the ELU function

Returns:

  • function := Elementwise operation

bayesian_models.math.GELU(x)

pytensor implementaion of the GELU activation function.

This function is defined as:

\[X \thicksim \mathcal{N}(0,1) f(x) \triangleq xP(X\le x) = x\Phi (x)=x \frac 12 [1+erf(\frac {x}{\sqrt{2}})]\]

Args:

  • x := Input tensor

Returns:

  • function := The elementwise operation

bayesian_models.math.ReLU(x, leak: float = 0.0)

pytensor implementation of the ReLU activation function:

\[f(x)\triangleq max(leak, x)\]

NOTE: With leak=0 this is the standard ReLU function. With leak a small number i.e. 1e-2 this is Leaky ReLU. Otherwise this is Parametric ReLU

Args:

  • x := The input tensor

  • leak:float=.0 := The leak parameter of the ReLU. When equal to 0, returns the standard ReLU, when equal to a small number i.e. 0.001 this is Leaky ReLU, otherwise it’s parametric ReLu

Returns:

  • function := Elementwise operation

bayesian_models.math.SWISS(x, beta: float = 1)

pytensor implementation of the Swiss activation function:

\[f(x) \triangleq x sigmoid(\beta x)\]

NOTE: This implementation is equivalent to the ‘Swiss-1’ activation function, where \(\beta\) is not learned. The original SWISS function has this as a learnable parameter instead

bayesian_models.math.SiLU(x)

pytensor implementation of the SiLU activation function. This function is defined as:

\[f(x) \triangleq x \sigma (x)\]

Args:

  • x := Input tensor

Returns:

  • function := The elementwise operation

bayesian_models.models module

class bayesian_models.models.BEST(nan_handling: str = <factory>, cast: ~numpy.dtype | None = <factory>, group_var: str | int | None = <factory>, effect_magnitude: bool = False, std_difference: bool = False, common_shape: bool = True, multivariate_likelihood: bool = False, _data_processor: ~bayesian_models.data.Data | None = <factory>, _initialized: bool | None = <factory>, _trained: bool | None = <factory>, save_path: str | None = None)

Bases: BESTBase

Bayesian Group difference estimation with pymc.

Kruschke’s Bayesian Estimation Superceeds the t-Test (BEST) model implementation for estimating differences between groups. The implementation is based on the official pymc documentation.

The model assumes StudentT likelihood over observations for added robustness. See the discussions section Bayesian Estimation Superceeds The t Test (BEST) for a more in depth explanation and motivation for this model

Class Attributes:

  • WarperFunction := Type definition

  • std_upper:float = 1e1 := Upper boundary for the standard deviations prior
  • std_lower:float = 1e0 := Lower boundary for standard deviations prior

Note

The original model has exceedingly wide priors:

\[\sigma_k \thicksim \mathcal{U}(10^{-3}, 10^{3})\]

These defaults are not sensible for most applications. [0.1-10] boundaries are implemented as defaults instead

  • ν_λ:float = 1/29.0 := Exponential decay parameter for the ν prior
  • ν_offset:float = 1 := Offset parameter for the ν prior. Since \(\nu \in [1,+ \infty])\) this should be left unchanged
  • ddof:int = 1 := Degrees of freedom parameter for empirical pooled standard deviations
  • std_diffusion_factor:int = 2 := Scalar multiplier for empirical pooled standard deviations on the μ prior. Controls how diffuse the prior is
  • zero_offset:float = 1e-4 := Small offset parameter to avoid numerical errors with pooled standard deviations
  • jax_device:str = ‘gpu’ := numpyro parameter for alternate sampling. Controls which device numpyro will use
  • jax_device_count: int =1 := numpyro setting. Number of devices to be used for HMC sampling (parallel)

Attention

Due to persistent problems with the numpyro dependency these parameters are ignored

Object Attributes:

  • group_var:str := Coordinate label for the categorical variable to group by

    Danger

    Due to issues with the underlying pymc implementation and limitations of numpy.isnan the categorical variables’ levels should be recorded as something castable to a float, if numpy array is used to store the data. It is recommended that a pandas.DataFrame be used instead

  • effect_magnitude:bool=False := Whether to compute an ‘effect size’ during inference. This metric is somewhat more more difficult to interpret, since it is no longer in the original units and is defined as:
    \[E=\dfrac{\Delta\mu_{1,2}}{\sqrt{\dfrac{ \sigma_{1}^{2}\sigma_{2}^{2}}{2}}}\]
  • std_differences:bool=False := Selects whether or not to estimate standard deviation differences between groups. Optional. Defaults to False. If effect_magnitude=True this value is ignored and the difference is computed automatically.
  • common_shape:bool=True := If True make the simplifying assumption that all input dimensions have the same shape parameter ν. Else, assign distinct shape parameters to all dimensions of the input array. Optional. Defaults to True. If switched off, warns of likely unidentified model.
  • multivariate_likelihood:bool=True := Flag signaling whether to use a multivariate likelihood or a univariate one. Optional.Defaults to False (use univariate likelihoods).

    Note

    The multivariate likelihood is always assumed to have a diagonal scale matrix. Hence this option is equivalent to independent univariates with the common degrees of freedom assumption, but is more computationally expensive and should be avoided

  • save_name:Optional[str]=None := A string specifying location and filename to save the model’s inference results. Optional. If set during objects’ construction, the save method may be called without an explicit save_path argument.
  • idata:Optional[arviz.InferenceData]=None := arviz.InferenceData object containing the results of model inference. Becomes set after calling the fit method
  • trained:bool=False := Sentinel signaling whether the model has been trained or not. Defaults to False. Should be switched on after calling fit. Prevents predict from being called on an object that has not been trained.
  • initialized:bool=False := Sentinel signaling whether the model has been full initialized. Defaults to False. Should be set after the object is called. Prevents fit and predict from being called prior to complete initialization.

Private Attributes:

  • var_names:dict[str:list[str]] := A dictionary with the ‘means’, ‘stds’ and ‘effect_magnitude’ keys, mapped to lists of the variables
  • _permutations:Optional[Iterable[tuple[str,str]]]=None := An iterable of groups per group_var. Contains all unique pairs of unique values of group_var.
  • _n_perms:Optional[int]=None := The number of groups.
  • levels:Optional[Iterable[str]] = None := Grouping variable levels. All unique values of group_var.
  • _ndims:Optional[int]=None := Number of input features. Only meaningful if common_shape is False.
  • num_levels:Optional[int]=None := The number of unique groups/ values of group_var.
  • coords := dict-like of dimension labels xarray coords. Will be inferred from inputs and used to label the posterior
  • _group_distributions:Optional[Dict[str, pymc.Distribution]]=None := A dict used internally to map inferred distributions. Defaults to None.
  • _model:Optional[pymc.Model] := The pymc.Model object

Object Methods:

  • __init__:= Begin initializing the object by setting all options, parameters and hyperparameters
  • __call__(data) := Initialize the model by specifying the full probability model according to options passed to __init__. Accepts a data structure and a label indicating the variable that defines the groups
  • fit(sampler, *args, **kwargs) := Perform inference on the model. sampler is valid sampler, i.e. pymc.sample or pymc.sampling.jax.sample_numpyro_nuts. All other arguments are forwarded to the sampler. Returns a arviz.InferenceData object containing the results of inference. Sets the trained and idata attributes
  • predict(var_names:Iterable[str], ropes:Iterable[tuple[float, float]], hdis=Iterable[float])->dict[str, pandas.DataFrame] := Compute results of group comparisons and return a dictionary mapping derived metrics to pandas.DataFrame objects containing inference summary. Decisions are made using the ROPE+HDI rule. Returns a dictionary mapping derived variable labels to pandas DataFrames containing the results. Accepts per variable rope limits and hdis. See the function for more details on these and other options
  • summary := Wrapper for arviz.summary. Returns summary results of model inference
  • plot_posterior := Wrapper for arviz.plot_posterior. Plot the inferred posterior
  • plot_trace := Wrapper for arviz.plot_trace. Plot inference results
  • _consistency_checks_ := Check that model parameters and hyperparameters are consistent and compatible
  • _preprocessing_ := Preprocess data. Delegates to the data module and calls the specified processor to preprocess the data
  • _fetch_differential_permutations_ := Compute all unique pairs of groups.

Class Methods:

Setters for all class attributes. Named set_attribute

  • set_std_upper(val:float)->None := Update the std_upper class attribute
  • set_std_lower(val:float)->None := Update the std_lower class attribute
  • set_shape_offset(val:float)->None := Update the ν_offset class attribute

    Caution

    Should generally not be modified

  • set_jax_device(device:str)->None := Update the jax_device class attribute
  • set_jax_device_count(val:int)->None := Update the jax_device_count class attribute
  • set_diffusion_factor(val:float)->None := Update the std_diffusion_factor attribute
  • set_degrees_of_freedom(val:int)->None := Update the ddof class attribute
cast: dtype | None
common_shape: bool
property coords: dict[str, Any] | None
effect_magnitude: bool
fit(*args, sampler=<function sample>, **kwargs) InferenceData

Perform inference by sampling from the posterior. infer is an alias for fit

Args:

  • sampler=pymc.sample := The pymc sampler to run MCMC with. Optional. Defaults to pymc.sample
  • *args:tuple[Any] := Arguements to be forwarded to the sampler
  • **kwargs:dict[str, Any] := Optional keyword arguments to be forwarded to the sampler

Returns:

  • idata:arviz.InferenceData := The results of inference

Raises:

  • RuntimeError := If called before fit has been called

Warns:

  • If any divergences are detected

group_var: str | int | None
property idata: InferenceData | None
infer(*args, sampler=<function sample>, **kwargs) InferenceData

Perform inference by sampling from the posterior. infer is an alias for fit

Args:

  • sampler=pymc.sample := The pymc sampler to run MCMC with. Optional. Defaults to pymc.sample
  • *args:tuple[Any] := Arguements to be forwarded to the sampler
  • **kwargs:dict[str, Any] := Optional keyword arguments to be forwarded to the sampler

Returns:

  • idata:arviz.InferenceData := The results of inference

Raises:

  • RuntimeError := If called before fit has been called

Warns:

  • If any divergences are detected

property initialized: bool
load(save_path: str | None = None) None

Load a pre trained model from the disk

Only meaningful for models saved with the ‘netcdf’ method. Otherwise, use ‘pickle’ directly instead

Caution

Not checks are being made that the posterior trace is compatible with model object

Args:

  • save_path:Optional[str] := File path to load the model from. If save_path has been provided at object initialization, it can be ignored

Returns:

  • None

classmethod mean(data, axis: int = 0)
property model: Model | None
multivariate_likelihood: bool
nan_handling: str
nan_present_flag: bool | None
num_levels: int | None
plot_posterior(*args, **kwargs)

Wrapper for arviz.plot_posterior

Plot Posterior densities in the style of John K. Kruschke’s book.

Args:

  • *args:tuple[Any] := Arguments to be forwarded to arviz.plot_posterior
  • **kwargs:dict[str, Any] := Keyword arguments to be forwarded to:code:arviz.plot_posterior

Returns:

  • graph:Any := The posterior plot object

plot_trace(*args, **kwargs)

Wrapper for arviz.plot_trace

Plot distribution (histogram or kernel density estimates) and sampled values or rank plot. If divergences data is available in sample_stats, will plot the location of divergences as dashed vertical lines.

Args:

  • *args:tuple[Any] := Arguments to be forwarded to arviz.plot_trace
  • **kwargs:dict[str, Any] := Keyword arguments to be forwarded to arviz.plot_trace

Returns:

  • plot:Any := Trace plot object

predict(var_names: Sequence[str] = ['Δμ'], ropes: Sequence[tuple[float, float]] = [(-0.1, 0.1)], hdis: Sequence[float] = [0.95], multilevel_on: str = '[', extend_summary: bool = True)

Render decisions on group differences, according to the ROPE+HDI rule:

  • HDI in ROPE := Not Significant (All plausible values are equivalent to 0)

  • HDI & ROPE == () := Significant (No plausible value is equivalent to zero)

  • HDI & ROPE != HDI :math:lor () := Withhold decision (‘Indeterminate’) (Some plausible values are equivalent to zero, other are not)

Aggregates results in a dictionary, mapping deterministic variable names to results dataframes. ROPE and HDI threshold limits are set on a dataframe wide level

Example usage:

from sklearn.datasets import load_iris
from bayesian_models.models import BEST
import pandas as pd

X, y = load_iris(return_X_y=True, as_frame=True)
names = load_iris().target_names
Y = y.replace(
    {i:name for i, name in enumerate(names)}
    )
df = pd.concat([X, Y], axis=1)
df.columns=df.columns[:-1].tolist()+["species"]
# Data
#        sepal length (cm)   ...   species
#    0                  5.1  ...   setosa
#    1                  4.9  ...   setosa
#    2                  4.7  ...   setosa
#    3                  4.6  ...   setosa
#    4                  5.0  ...   setosa
#    ...                ...  ...     ...
#    145                6.7  ...   virginica
#    146                6.3  ...   virginica
#    147                6.5  ...   virginica
#    148                6.2  ...   virginica
#    149                5.9  ...   virginica

obj = BEST()(df, "species")
obj.fit()
results = obj.predict() # Only 'Δμ' by default
print(results['Δμ'])
# Output
#                                            Significance
# Δμ(setosa, versicolor)  sepal length (cm) Indeterminate
#                        sepal width (cm)   Indeterminate
#                        petal length (cm)  Indeterminate
#                        petal width (cm)   Indeterminate
# Δμ(setosa, virginica)  sepal length (cm)  Indeterminate
#                        sepal width (cm)   Indeterminate
#                        petal length (cm)  Indeterminate
#                        petal width (cm)   Indeterminate
# Δμ(versicolor, sepal length (cm)          Indeterminate
#                       sepal width (cm)    Indeterminate
#                        petal length (cm)  Indeterminate
#                        petal width (cm)   Indeterminate

Args:

  • var_names:Iterable[str]=[‘Δμ’] := An iterable of derived metrics to return. Optional. Defaults to returning expected difference. Default names are ‘Δμ’ for the difference of means, ‘Δσ’ for the difference of standard deviations and ‘Effect_Size’ for Kruschkes effect size.
  • ropes:Iterable[tuple[float, float]] := An Iterable of length-2 tuples of floats, defining the Region Of Practical Equivalence. Each rope is applied to all features for every variable in var_names.
  • hdis:Iterable[float] := An iterable of non-negative floats defining the probability threshold for the credible interval. Is applied to all features for each variable in var_names
  • multilevel_on:str=’[’ := A separator defining the multilevel index. pymc by default concatinates the label according to the form: {var_name}[{feature_label}]. The argument will reindex them in a multilevel fashion of the form (var_name, feature_label) in the resulting dataframe. Set to None to disable this behavior.
  • extend_summary:bool=True := If True the new Significance column extends the summary dataframe. Else return a new dataframe containing only the Significance results. Optional. Defaults to True and returns an extended version of the summary.

Returns:

  • results:dict[str,pandas.DataFrame] := Decision results. Returned in the form of dictionary, whose keys are the names of deterministic quantities (i.e. ‘Δμ’ ‘Δσ’ ‘E’ ‘ν’). Items are pandas.DataFrame object containing summary results (like those returned by arviz.summary) with an additional column, named Significance containing the decision
save(save_path: str | None = None, method: str = 'netcdf') None

Save the model object for later reuse

Available save methods are ‘netcdf’ and ‘pickle’. The latter is discouraged and has known problems. For the ‘netcdf’ method the posterior trace will be saved.

Caution

At present, no checks are being made to verify that the posterior is compatible with the model object

Args:

  • save_path:Optional[str] := The file path to save the model to. If save_path has been provided at model initialization, need not be provided
  • method:str=’netcdf’ := Which method to use to save the model. For the ‘netcdf’ method, only the posterior trance is save and consequently reloaded. For the ‘pickle’ method, attempts to serialize the entire model. The latter case should be avoided

Returns:

  • None

save_path: str | None
classmethod set_degrees_of_freedom(val: int) None
classmethod set_diffusion_factor(val: float) None
classmethod set_jax_device(device: str) None
classmethod set_jax_device_count(val: int) None
classmethod set_mean_of_means(func: Callable[[...], ndarray[Any, dtype[ScalarType]]]) None
classmethod set_shape_factor(val: float) None
classmethod set_shape_offset(val: float) None
classmethod set_std_lower(val: float) None
classmethod set_std_of_means(func: Callable[[...], ndarray[Any, dtype[ScalarType]]]) None
classmethod set_std_upper(val: float) None
classmethod std(data, ddof: int | None = None, scale: int | None = None, zero_offset: float | None = None, axis: int = 0)
std_difference: bool
summary(*args, **kwargs) DataArray | DataFrame

Wrapper for arviz.summary(idata)

Args:

  • *args:tuple[Any] := Arguments to be forwarded to arviz.summary
  • **kwargs:dict[str, Any] := Keyword arguments to be forwarded to arviz.summary

Returns:

  • summary_results:xarray.DataArray := Summary results

property trained: bool
var_names: dict[str, list]
static warp_input(data, row_indexer, column_indexer, transform, unwrap: bool = True)

Utility method that selects a subset of the data and applies transform one it.

Used to supply the data or values extracted form the data(mean, standard deviation) to the computation graph

Args:

  • data:Any := The data to process
  • row_indexer:Any := Indexer for row selection
  • column_indexer:Any := Indexer for column selection
  • transform:Callable:= A callable that takes a data structure and returns a data structure
  • unwrap:bool=True := When True unwraps the resulting pandas.DataFrame to the underlying numpy.NDArray object. Optional. Defaults to True and returns a numpy array object

Returns:

  • ndf:bayesian_models.Data := A group of the original Data
  • warped_input:bayesian_models.Data := The output of transform
class bayesian_models.models.BayesianEstimator

Bases: BayesianModel

Abstract base class for “predictive” style models.

These models take some input information X and return some output predicted quantity Y.

abstract property posterior_trace
class bayesian_models.models.BayesianModel

Bases: ABC

Abstract base class for all Bayesian Models in pymc.

Defines a common API for all model objects

Object Methods:

  • __init__ := Begin initializing the model by setting all of the models parameters and hyperparameters. If a model has multiple variations, these are set here. The subclass should define valid hyperparameters as class or object attributes. Object level properties should be preferred where a user is expected to need to change these parameters for a single dataset. Class level parameters are preferred where a user is likely to want to apply the same model to multiple data (with the same parameters)
  • __call__ := Initialize the object by specifying the full probability model for inference. This method should also receive the training data. These should be set using pymc.Data containers. The data received should be placed in a Data container, supplied by the data submodule for preprocessing/ For most simple, and predictive models, that accept some input information and attempt to predict some output quantity, the inputs should be declared as mutable shared tensors pymc.Data(name, X, mutable=True) and the predict method should invoke pymc.set_data(inputs) to replace the input tensor with a new one. For other special cases see the predict method. Should return the object itself for easy method chaining. Should set the objects’ initialized property to signal that the fit method can be called.
  • fit := Sample from the posterior according to the sampler argument. Forwards all other arguments to the sampler, sets the models’ idata and trained flag, signaling the predict and other posterior methods can be called. infer is an alias for fit
  • predict := Produce output from the model. The implementation details of this method, vary depending on the model.
    • For predictive type models that attempt to predict some Y based on some X, this method should sample from the posterior predictive and return an appropriate Y.
      • For most simple models should call pymc.set_data(dict(inputs=X_new)) and sample y_obs from the posterior predictive.

        Example:

        def predict(self, Xnew, ...):
            with self.model:
                pm.set_data(dict(inputs=Xnew))
                y = pm.sample_posterior()
            return y
        
      • For models with special predictive APIs like Gaussian Process models, should declare a new variable as a shared tensor pymc.Data(X_new, mutable=True) the first time predictions are made, additional nodes corresponding to the special API (i.e. gp.condintional) and any further postprocessing nodes corresponding to data transforms and response functions. Further calls to this method should invoke pymc.set_data to replace the previous inputs with the new ones followed by pymc.sample_posterior_predictive.

        Example:

        def predict(self, Xnew):
            with self.model:
                if not self.predictive_initialized:
                    predicted = pm.Data(
                        'predicted',
                        Xnew, 
                        mutable=True
                        )
                ...
                ynew = pm.sample_posterior_predictive()
                return ynew
        
      • For non-predictive models (i.e. oversampling models, statistical comparison models etc), data node(s) are immutable and predict should perform the equivalent operation for these models (i.e. render importance decisions), yield augmented or rebalanced datasets etc.
  • plot_trace := Wrapper for arviz.plot_posterior

  • plot_posterior := Wrapper for arviz.plot_posterior

  • summary := Wrapper for arviz.summary

abstract fit()
abstract property idata
abstract property initialized
abstract load()
abstract property model
abstract predict()
abstract save()
abstract property save_path
abstract property trained
bayesian_models.models.ELU(x, alpha: float = 1.0)

pytensor implementation of the ELU activation function:

\[f(x) \triangleq \begin{cases} x & x \gt 0 \\ \alpha (e^x-1) &\text{if } b \\ \end{cases}\]

Args:

  • x := The input tensor

  • alpha:float=1.0 := The \(\alpha\) parameter of the ELU function

Returns:

  • function := Elementwise operation

bayesian_models.models.GELU(x)

pytensor implementaion of the GELU activation function.

This function is defined as:

\[X \thicksim \mathcal{N}(0,1) f(x) \triangleq xP(X\le x) = x\Phi (x)=x \frac 12 [1+erf(\frac {x}{\sqrt{2}})]\]

Args:

  • x := Input tensor

Returns:

  • function := The elementwise operation

bayesian_models.models.ReLU(x, leak: float = 0.0)

pytensor implementation of the ReLU activation function:

\[f(x)\triangleq max(leak, x)\]

NOTE: With leak=0 this is the standard ReLU function. With leak a small number i.e. 1e-2 this is Leaky ReLU. Otherwise this is Parametric ReLU

Args:

  • x := The input tensor

  • leak:float=.0 := The leak parameter of the ReLU. When equal to 0, returns the standard ReLU, when equal to a small number i.e. 0.001 this is Leaky ReLU, otherwise it’s parametric ReLu

Returns:

  • function := Elementwise operation

bayesian_models.models.SWISS(x, beta: float = 1)

pytensor implementation of the Swiss activation function:

\[f(x) \triangleq x sigmoid(\beta x)\]

NOTE: This implementation is equivalent to the ‘Swiss-1’ activation function, where \(\beta\) is not learned. The original SWISS function has this as a learnable parameter instead

bayesian_models.models.SiLU(x)

pytensor implementation of the SiLU activation function. This function is defined as:

\[f(x) \triangleq x \sigma (x)\]

Args:

  • x := Input tensor

Returns:

  • function := The elementwise operation

bayesian_models.typing module

bayesian_models.utilities module

class bayesian_models.utilities.DictTable

Bases: dict

Jupyter utility class that overrides the dicts’ defaults __repr__ rendering the input dictionary to an HTML table for convenient jupyter rendering

class bayesian_models.utilities.SklearnDataFrameScaler(scaler: Callable[[...], Any], backend: str = 'pandas', *args, **kwargs)

Bases: object

Extend the functionality of sklearn scalers, allowing for labeled inputs and outputs

Adds labels to the result of sklearn scalers

Args:

  • scaler:Callable[[…], tuple[numpy.ndarray]] := The scaler Callable. Must use the class based API
  • backend:str=’pandas’ := Which label matrix backend to use. Valid options are ‘pandas’ and ‘xarray’

Returns:

  • scaler_arrays:tuple[pd.DataFrame, xarray.DataArray] := A tuple of rescaled and relabeled arrays
bayesian_models.utilities.count_missing_nan(df: DataFrame, axis: int = 0)

Return a new DataFrame with the counts of missing and invalid values across specified axis.

Args:

  • df:pandas.DataFrame := The data

  • axis:int=0 := The axis across which missing

values will be enumerated. Defaults to 0 (show missing values in each column)

Returns:

  • missing_df:pd.DataFrame := A DataFrame containing

counts of missing values

bayesian_models.utilities.dataarray_from_pandas(df: DataFrame, dim_names=['dim_0', 'dim_1'], **kwargs)

Convert a pandas.DataFrame to an equivalent xarray.DataArray

Args:

  • df:pandas.DataFrame := The pandas.DataFrame to convert

  • dim_names:Sequence[Hashable] := A sequence of Hashable

names to be used for the two axis. Optional. Defaults to the names ‘dim_0’ and ‘dim_1’.

  • **kwargs:dict[Any,Any] := Keyword arguements to be

forwarded to xarray.DataArray constructor. Optional

Returns:

  • converted:xarray.DataArray := The converted dataframe

bayesian_models.utilities.dict_powerset(dictionary: dict, keys_only: bool = False) Iterable

Dictionary powerset function. Lazily returns all possible ‘sub-dictionaries’ from an input dict - including an emtpy dict. Returns entire dicts if keys_only=True or tuples of keys otherwise. Examples:

bayesian_models.utilities.dirichlet_moments(a: ndarray, standardize: bool = True)

Calculate the Dirichlet distributions’ critical moments. A dirichlet is fully specified by it’s first two moments, i.e. mean and variance

Args:

  • shape:Sequence:= The shape parameter(α) of the

Dirichlet. First dimention is assumed to by sepperate Dirichlets and the last dimention defines the shape

  • standardize:bool=True := If true standardizes

the variance, returning standard deviation. Else returns plain second order central moment i.e. the variance. Optional. Defalts to True.

Returns:

  • dirich_moments:xarray.Dataset := An xarray.Dataset

containing the calculcate moments. Always has the ‘variance’ and ‘mean’ data variables, and if standardize=True also contains the ‘std_dev’ data variable

Raises:

  • ValueError:= If the input a cannot be coerced into

an array-like structure, via a.values

bayesian_models.utilities.extract_dist_shape(dist: Type[Distribution]) list[str]
bayesian_models.utilities.flatten(obj: Iterable)

Flatten a nested iterable

Recursively flatten arbitrary an arbitrary input iterable, yielding values iteratively.

Args:

  • obj:Iterable := The nested iterable to flatten

Yields:

  • element:Any := Each non-iterable element in the array
bayesian_models.utilities.gen_masked_predictions(model, masked_generator, baseline_truth, metrics: list[typing.Callable[..., typing.Any]] = [functools.partial(<function mean_squared_error>, squared=False)], return_elements: bool = False, **kwargs)

Generate performance metric evaluations on masked inputs.

Args:

  • model:= The model to generate predictions from

  • masked_generator:= Masked inputs generator. Firstmost

element must be ground truth, i.e. fully unmasked inputs

  • baseline_truth:np.ndarray := Array of values to be used

as ground truths. Will be expanded during evaluation process

  • metrics:list[Callable[…,Any]] := Metrics to be used in

the assessment of the A.N.N. predictions. Currently only a single metric is supported. The metric should be a Callable accepting a baseline truth tensor, a predictions tensor and a sample_dim arguement. Currently only single rank inputs are supported and the sample_dim determines the features axis.

  • return_inputs:bool=True := Selects whether to return detected

inputs or just the absolute indices of the masks.

  • kwargs:dict[str,Any]:= Keyword arguments to be forwarded

to, among other places model.predict

Returns:

  • Measures:collections.namedtuple := A namedtupe containing

the metric evaluation for the masks and optionally the corresponding inputs. Has three fields:

  • iteration:int>=1 := Enumerates the current iteration

  • measures:numpy.ndarray := Array of metric evaluations

for the masks. For code consistency, is a rank-4 tensor of the form distribution_moment x permutation x sample x features of the general form 1 x batch_size x 1 x 1.

  • inputs:Optional[xarray.DataArray]=None := If

return_elements=True if an xarray.DataArray containing the masked inputs, otherwise is None. The array is a rank-3 tensor of permutations x samples x features. Defaults to non-empty field.

bayesian_models.utilities.invert_dict(e)
bayesian_models.utilities.list_difference(l1, l2)
bayesian_models.utilities.mean_squared_error(true: ndarray[Any, dtype[ScalarType]], predicted: ndarray[Any, dtype[ScalarType]], sample_weights=None, squared: bool = True, mean: bool = True, average: bool = True, sample_dim: int = 0)

Squared Error implementation, based on sklearn.metrics.mean_squared_error with more options.

Args:

  • true:numpy.typing.NDArray := Array of true values

  • predicted:numpy.typing.NDArray := Array of predicted values

  • mean:bool=True := Selects whether to calculate the mean of

error across all samples or return indevidual errors. Optional Defaults to True (and return Mean Squared Error)

  • average:bool=True := Selects how to handle multidimentional

inputs. If True (default) averages over the outputs axis. With The averaging behavior is determined by sample_weights. If None then performs uniform averaging, otherwise returns a weighted average. If False averaging is done, and errors are returned for each output. Optional. Defaults to True and returns uniform average MSE.

  • sample_weights:Optional[np.typing.NDArray] := An array of

weights to be used during averaging over the outputs dimention. Must be of appropriate length and is ignored is average=False. If None the average is uniform. Optional. Defaults to None and returns uniform averaging.

  • sample_dim:int=0 := Specifies the sample dimention. Optional.

Defaults to 0.

Returns:

  • errors:numpy.ndarray := An array of errors. Either mse, if

mean=True and squared=True, rmse if squared=False, squared error if mean=False and squared=True or error if mean=False and squared=False:

  • mean=True`and `average=True := Scalar mse

  • mean=True and average=False := Output-length vector

of errors for each output

  • mean=False and average=True := observations-length

vector of averaged error for each test sample

  • mean=False and average=False := 2D array, of the same

shape as the inputs

bayesian_models.utilities.package_dirichlet_predictions(raw_preds, outputs, inputs=None, model=None) DataArray

Converts the raw numpy tensor output of an A.N.N to a human-readable xarray.DataArray, with optional post-processing

Args:

  • raw_preds:numpy.ndarray := The output of the

tf.model.predict

  • outputs:xarray.DataArray := The test set of

the N.N., from which names and labels will be infered.

  • inputs:Optional[xarray.DataArray] := The inputs

to the model. Should only be prodived if the inputs were masked, and this should be the unmasked tensor, from which appropriate reshape will be infered. First two dimentions are assumed to be of permutation x sample. Optional. Defaults to None (ignored and no reshaping will be attempted).

model:Optional[tf.keras.model]=None := The model, whose metadata will be extracted and added to the resulting DataArray’s attributes. Optional. Currently not implemented.

bayesian_models.utilities.powerset(sequence: Sequence) Iterable

Powerset implementation in pure python. Returns all possible ‘subsets’ of input sequence, including the empty set. Evaluation is lazy, and each element returned is a tuple of the elements of the original iterable. Example:

bayesian_models.utilities.query_multiple(df, col, multiquery)
bayesian_models.utilities.reverse_tidy_multiindex(df: DataFrame, sep='.')

Convert a tidy dataframe to hierarchically indexed one based on separator delimiters

Reverses the tidying to a hierarchical format. Different levels of the index are identified based on “sep”

Args:

  • df:pandas.DataFrame := The dataframe to process

  • sep:str=’_._’ := The string delimiter, separating values for different levels of the index

Returns:

  • ndf:pandas.DataFrame := The dataframe with hierarchical index

bayesian_models.utilities.rowwise_value_counts(df: DataFrame)

Returns row-wise counts of values for categorical variables.

Args:

  • df:pandas.DataFrame := The dataframe to process

Returns:

  • counts:pandas.DataFrame := A new DataFrame of counts of

distinct values in the input dataframe

bayesian_models.utilities.select_subarray(df: DataFrame, targets: list[tuple[str, str, str]], indicators: list[tuple[str, str, str]], scaleX: bool = True, train_split: bool = False, mappings: dict[str, Union[str, int, float]] | None = None, dummify: bool = False) tuple[pandas.core.frame.DataFrame, pandas.core.frame.DataFrame]
bayesian_models.utilities.std_scale(df)
bayesian_models.utilities.tidy_multiindex(df: DataFrame, sep: str = '.')

Convert a hierarchically indexed pandas.DataFrame to tidy formated one

Compress a hierarchically indexed dataframe to standardized tidy format. A unique sepperator sep is used to allow reversal. All levels of the index are appended together with a delimeter to allow reversals.

Args:

  • df:pandas.DataFrame := A pandas.DataFrame hierarchically indexed
  • sep:str=’_._’ := A delimenter delineating the different levels of the index. Ensure it is not present in any column name to avoid a malformed index

Returns:

  • ndf:pandas.DataFrame := The DataFrame with a single-level index
bayesian_models.utilities.undummify(df: DataFrame, cols: list[str, tuple[str]], ncol_name: str | tuple[str], sep: str | None = None, rmap: dict[int, Union[str, tuple[str]]] | None = None) DataFrame

Reverses hot-encoded variables in the DataFrame. A series of hot-encoded variable levels $(i_1, i2, dots, i_k)$ is mapped to a single new column $(k)$, whose name is specified by ncol_name, in the new dataframe. Previous level columns are dropped.

Args:

  • df:pandas.DataFrame := The DataFrame to operate upon

  • cols:list[str, tuple[str]] := A list of columns, representing

the levels of a categorical variable

  • sep:Optional[str] := sepperator for variable level. Currently

ignored

  • ncol_name:Union[str, tuple[str]] := Name of the new categorical

column

  • remap:Optional[dict[int, Union[str, tuple[str]]]] := A

dictionary mapping of categorical levels to values. Keys are the assumed to be levels, values are assumed to be values (i.e. strings). When provided, the previous levels will be replaced by the specified mappings in the new DataFrame

Returns:

  • ndf:pandas.DataFrame := The processed dataframe