pymc.CustomDist#

class pymc.CustomDist(name, *dist_params, dist=None, random=None, logp=None, logcdf=None, moment=None, ndim_supp=0, ndims_params=None, dtype='floatX', **kwargs)[源代码]#

一个用于创建自定义分布的帮助类

此类可用于包装黑盒随机和logp方法,以便在前向和mcmc采样中使用。

用户可以提供一个 dist 函数,该函数返回一个由更简单的 PyMC 分布构建的 PyTensor 图,该图表示分布。此图用于进行随机抽取,并在用户未提供时自动推断 logp 表达式。

另外,用户可以提供一个 random 函数,该函数返回数值抽取结果(例如,通过 NumPy 例程),以及一个 logp 函数,该函数必须返回一个 Python 图,当评估时表示 logp 图。这用于 MCMC 采样。

此外,用户可以提供 logcdfmoment 函数,这些函数必须返回一个计算这些量的 PyTensor 图。这些可能会被其他 PyMC 例程使用。

参数:
名称 : strstr
dist_params元组

分布参数的序列。这些将在内部转换为 Pytensor 张量变量。

dist: Optional[Callable]

一个返回从更简单的 PyMC 分布构建的 PyTensor 图的可调用对象,该图表示分布。PyMC 可以使用它来进行随机抽取,并且在某些情况下推断分布的对数概率。在这种情况下,不需要实现 randomlogp 函数。

它必须有以下签名:dist(*dist_params, size)。符号张量分布参数作为位置参数传递,顺序与它们在构建 CustomDist 时提供的顺序相同。

random可选的[可调用]

一个可调用的函数,用于从分布中生成随机抽样

它必须具有以下签名:random(*dist_params, rng=None, size=None)。数值分布参数作为位置参数传递,顺序与它们在构造 CustomDist 时提供的顺序相同。关键字参数是 rng,它将提供随机变量关联的 Generator,以及 size,它将表示所需随机抽取的大小。如果为 None,则在尝试从分布的先验或后验预测中抽取随机样本时,将引发 NotImplemented 错误。

logp可选的[可调用]

一个计算给定 value 在某些分布参数值条件下的对数概率的可调用对象。它必须具有以下签名:logp(value, *dist_params),其中 value 是一个表示分布值的 PyTensor 张量,而 dist_params 是持有分布参数值的张量。该函数必须返回一个 PyTensor 张量。

当指定了 dist 函数时,PyMC 将尝试在没有提供的情况下自动推断 logp

否则,在尝试计算分布的对数概率时,将引发 NotImplementedError

logcdf可选的[可调用]

一个计算给定 value 在某些分布参数值条件下的对数累积概率的可调用对象。它必须具有以下签名:logcdf(value, *dist_params),其中 value 是一个表示分布值的 PyTensor 张量,而 dist_params 是保存分布参数值的张量。此函数必须返回一个 PyTensor 张量。如果为 None,则在尝试计算分布的对数累积分布函数时将引发 NotImplementedError

moment可选的[可调用]

一个可用于计算分布矩的函数。它必须具有以下签名:moment(rv, size, *rv_inputs)。分布的变量作为第一个参数 rv 传递。size 是由 dimssize 和提供给分布的参数隐含的随机变量的大小。最后,rv_inputs 是分布参数的序列,顺序与创建 CustomDist 时提供的顺序相同。如果为 None,将分配一个默认的 moment 函数,该函数将始终返回 0 或零数组。

ndim_suppint

分布支持中的维度数量。默认假设为标量分布,即 ndim_supp = 0

ndims_paramsOptional[Sequence[int]]

每个分布参数支持中的维度数量列表。如果为 None ,则假定所有参数都是标量,因此它们的支持维度数将为 0。如果提供了 PyTensor 分布函数,则不需要此项。

dtypestr

分布的 dtype。所有传递给分布的抽取和观察值都将被转换为此 dtype。如果提供了 PyTensor 分布函数,则不需要此项,因为该函数应已返回正确的 dtype!

class_namestr

用于包装 CustomDist 方法的类的名称。如果未指定,将使用模型变量的名称。

kwargs

额外的关键字参数被传递给父类的 __new__ 方法。

示例

创建一个自定义的 CustomDist,它封装了一个黑箱 logp 函数。由于没有提供随机函数,因此该变量不能用于先验或后验预测采样。

import numpy as np
import pymc as pm
from pytensor.tensor import TensorVariable

def logp(value: TensorVariable, mu: TensorVariable) -> TensorVariable:
    return -(value - mu)**2

with pm.Model():
    mu = pm.Normal('mu',0,1)
    pm.CustomDist(
        'custom_dist',
        mu,
        logp=logp,
        observed=np.random.randn(100),
    )
    idata = pm.sample(100)

提供一个返回数值抽取的随机函数。这允许在先验和后验预测采样中使用 CustomDist。

from typing import Optional, Tuple

import numpy as np
import pymc as pm
from pytensor.tensor import TensorVariable

def logp(value: TensorVariable, mu: TensorVariable) -> TensorVariable:
    return -(value - mu)**2

def random(
    mu: np.ndarray | float,
    rng: Optional[np.random.Generator] = None,
    size : Optional[Tuple[int]]=None,
) -> np.ndarray | float :
    return rng.normal(loc=mu, scale=1, size=size)

with pm.Model():
    mu = pm.Normal('mu', 0 , 1)
    pm.CustomDist(
        'custom_dist',
        mu,
        logp=logp,
        random=random,
        observed=np.random.randn(100, 3),
        size=(100, 3),
    )
    prior = pm.sample_prior_predictive(10)

提供一个 dist 函数,该函数创建一个由其他 PyMC 分布构建的 PyTensor 图。PyMC 可以自动推断出该变量的 logp 对应于一个偏移的指数分布。

import pymc as pm
from pytensor.tensor import TensorVariable

def dist(
    lam: TensorVariable,
    shift: TensorVariable,
    size: TensorVariable,
) -> TensorVariable:
    return pm.Exponential.dist(lam, size=size) + shift

with pm.Model() as m:
    lam = pm.HalfNormal("lam")
    shift = -1
    pm.CustomDist(
        "custom_dist",
        lam,
        shift,
        dist=dist,
        observed=[-1, -1, 0],
    )

    prior = pm.sample_prior_predictive()
    posterior = pm.sample()

提供一个 dist 函数,该函数创建一个由其他 PyMC 分布构建的 PyTensor 图。PyMC 可以自动推断出该变量的 logp 对应于一个修正的 PERT 分布。

import pymc as pm
from pytensor.tensor import TensorVariable

 def pert(
     low: Tensorvariable,
     peak: Tensorvariable,
     high: Tensorvariable,
     lmbda: Tensorvariable,
     size: Tensorvariable,
 ) -> Tensorvariable:
     range = (high - low)
     s_alpha = 1 + lmbda * (peak - low) / range
     s_beta = 1 + lmbda * (high - peak) / range
     return pm.Beta.dist(s_alpha, s_beta, size=size) * range + low

 with pm.Model() as m:
     low = pm.Normal("low", 0, 10)
     peak = pm.Normal("peak", 50, 10)
     high = pm.Normal("high", 100, 10)
     lmbda = 4
     pm.CustomDist("pert", low, peak, high, lmbda, dist=pert, observed=[30, 35, 73])

 m.point_logps()

方法

CustomDist.__init__(*args, **kwargs)

CustomDist.check_valid_dist_random(dist, ...)

CustomDist.dist(*dist_params[, dist, ...])

CustomDist.is_symbolic_random(random, ...)

CustomDist.parse_dist_params(dist_params)