Pymc3:如何定义参数的有序向量
Pymc3: how to defined an ordered vector of parameters
我正在尝试进行有序逻辑回归,其中一个参数是切割点的有序向量。我不确定如何定义它们。
我想出的一个非常愚蠢的方法是手动定义矢量的每个分量,使用一个作为另一个的边界:
with pm.Model() as bound_model:
a = pm.Normal('a', mu=0, sd=10)
BoundedB = pm.Bound(pm.Normal, upper=a)
b = BoundedB('b', mu=0, sd=10)
BoundedC = pm.Bound(pm.Normal, upper=b)
c = BoundedC('c', mu=0, sd=10)
bound_trace = pm.sample(1000)
这效率不高,我不确定它们是否会按预期工作。有更好的方法吗?
我猜这是 pymc3 中缺少的功能。我可能会写一个拉取请求,但与此同时你可以使用这样的东西:
class Ordered(pymc3.distributions.transforms.ElemwiseTransform):
name = "ordered"
def forward(self, x):
out = tt.zeros(x.shape)
out = tt.inc_subtensor(out[0], x[0])
out = tt.inc_subtensor(out[1:], tt.log(x[1:] - x[:-1]))
return out
def backward(self, y):
out = tt.zeros(y.shape)
out = tt.inc_subtensor(out[0], y[0])
out = tt.inc_subtensor(out[1:], tt.exp(y[1:]))
return tt.cumsum(out)
def jacobian_det(self, y):
return tt.sum(y[1:])
并像这样使用它:
N = 10
with pm.Model() as model:
pm.Normal('y', mu=np.zeros(N), sd=1, shape=N,
transform=Ordered(), testval=np.arange(N))
编辑:一个非常关于这里发生的事情的简短解释:
我们通过
定义从 $R^n$ 到有序序列集的映射
f(x_1) = x_1,\quad f(x_i) = f(x_{i - 1}) + exp(x_i)
由于这是一个很好的双射函数,我们可以通过
计算$R^n$上的概率密度
P_{R^n}(x) = P_{ordered}(f(x)) \cdot |J_{f(x)}|
其中 J 是变换的雅可比矩阵。
采样器只会看到不受约束的值。这几乎就是 Bound
最初的实现方式。
如果您想了解更多详情,可以查看stan manual。它包含对这些转换的很好描述,并且 pymc3 和 stan 的数学相同。
我正在尝试进行有序逻辑回归,其中一个参数是切割点的有序向量。我不确定如何定义它们。
我想出的一个非常愚蠢的方法是手动定义矢量的每个分量,使用一个作为另一个的边界:
with pm.Model() as bound_model:
a = pm.Normal('a', mu=0, sd=10)
BoundedB = pm.Bound(pm.Normal, upper=a)
b = BoundedB('b', mu=0, sd=10)
BoundedC = pm.Bound(pm.Normal, upper=b)
c = BoundedC('c', mu=0, sd=10)
bound_trace = pm.sample(1000)
这效率不高,我不确定它们是否会按预期工作。有更好的方法吗?
我猜这是 pymc3 中缺少的功能。我可能会写一个拉取请求,但与此同时你可以使用这样的东西:
class Ordered(pymc3.distributions.transforms.ElemwiseTransform):
name = "ordered"
def forward(self, x):
out = tt.zeros(x.shape)
out = tt.inc_subtensor(out[0], x[0])
out = tt.inc_subtensor(out[1:], tt.log(x[1:] - x[:-1]))
return out
def backward(self, y):
out = tt.zeros(y.shape)
out = tt.inc_subtensor(out[0], y[0])
out = tt.inc_subtensor(out[1:], tt.exp(y[1:]))
return tt.cumsum(out)
def jacobian_det(self, y):
return tt.sum(y[1:])
并像这样使用它:
N = 10
with pm.Model() as model:
pm.Normal('y', mu=np.zeros(N), sd=1, shape=N,
transform=Ordered(), testval=np.arange(N))
编辑:一个非常关于这里发生的事情的简短解释:
我们通过
定义从 $R^n$ 到有序序列集的映射f(x_1) = x_1,\quad f(x_i) = f(x_{i - 1}) + exp(x_i)
由于这是一个很好的双射函数,我们可以通过
计算$R^n$上的概率密度P_{R^n}(x) = P_{ordered}(f(x)) \cdot |J_{f(x)}|
其中 J 是变换的雅可比矩阵。
采样器只会看到不受约束的值。这几乎就是 Bound
最初的实现方式。
如果您想了解更多详情,可以查看stan manual。它包含对这些转换的很好描述,并且 pymc3 和 stan 的数学相同。