PyMC3和大型数据集的贝叶斯线性回归 - 括号嵌套级别超过最大值且性能缓慢

3
我希望使用贝叶斯多元线性回归来估计团体运动中球员的实力(例如冰球、篮球或足球)。为此,我创建了一个矩阵X,其中包含球员作为列和比赛作为行。对于每场比赛,球员条目是1(球员在主队中出场)、-1(球员在客队中出场)或0(球员不参加此场比赛)。因此,在每场比赛中,依赖变量Y被定义为两个队的得分差(主队得分-客队得分)。
因此,一个赛季的参数数量将非常大(例如,X由300行x450列定义;即450个球员系数+y截距)。当运行拟合时,我遇到了编译错误:
('Compilation failed (return status=1): /Users/me/.theano/compiledir_Darwin-17.7.0-x86_64-i386-64bit-i386-3.6.5-64/tmpdxxc2379/mod.cpp:27598:32: fatal error: bracket nesting level exceeded maximum of 256.

我尝试通过设置来处理这个错误:

theano.config.gcc.cxxflags = "-fbracket-depth=1024"

现在,抽样正在运行。然而,即使我只取300行中的35行,抽样也需要20分钟以上才能完成。
这是我的基本代码:
import pymc3 as pm
basic_model = pm.Model()

with basic_model:

    # Priors for beta coefficients - these are the coefficients of the players
    dict_betas = {}
    for col in X.columns:
        dict_betas[col] = pm.Normal(col, mu=0, sd=10)

    # Priors for unknown model parameters
    alpha = pm.Normal('alpha', mu=0, sd=10) # alpha is the y-intercept
    sigma = pm.HalfNormal('sigma', sd=1) # standard deviation of the observations

    # Expected value of outcome
    mu = alpha
    for col in X.columns:
        mu = mu + dict_betas[col] * X[col] # mu = alpha + beta_1 * Player_1 + beta_2 * Player_2 + ...

    # Likelihood (sampling distribution) of observations
    Y_obs = pm.Normal('Y_obs', mu=mu, sd=sigma, observed=Y)

对于大型数据集,模型实例化只需要一分钟的时间。我使用以下方法进行抽样:

with basic_model:

    # draw 500 posterior samples
    trace = pm.sample(500)

小样本量(例如9行,80列)的采样在7分钟内完成。然而,随着样本量的增加,时间显著增加。
有什么建议可以使这个贝叶斯线性回归在合理的时间内运行?这种问题是否可用PyMC3解决(记得我遇到了一个括号嵌套错误)?我在最近的一篇论文中看到,这种分析在R中是可行的(https://arxiv.org/pdf/1810.08032.pdf)。因此,我想它也应该在Python 3中以某种方式工作。
感谢任何帮助!

1
也许尝试将其转换为点积形式,而不是使用“for”循环。类似于beta = pm.Normal('beta', mu=0, sd=10, shape=X.shape[1])mu = alpha + pm.math.dot(X, beta)。也许这个答案可能会有所帮助,它还演示了如何增加X以包括截距并避免单独使用alpha变量。 - merv
Merv,非常感谢您的有益评论。您建议使用点积而不是for循环/字典解决了括号嵌套问题和性能缓慢问题。程序在所有beta设置为mu = 0时运行良好。但是,现在我不知道如何为每个玩家包含不同的mus?是否有一种方法可以使用您建议的beta定义来包含不同的mus和sigmas到beta中?最终,我想为每个玩家使用不同的先验运行贝叶斯线性回归。 - P. Rinter
1个回答

4
消除for循环应当提升性能并且可能也解决你所报告的嵌套问题。Theano的TensorVariables和由它们派生的PyMC3随机变量已经是多维的,并支持线性代数操作。试着将你的代码改为以下示例:
beta = pm.Normal('beta', mu=0, sd=10, shape=X.shape[1])
...
mu = alpha + pm.math.dot(X, beta)
...

如果您需要为mu和/或sd指定不同的先验值,这些参数接受theano.tensor.as_tensor_variable()接受的任何内容,因此可以传递列表或numpy数组。
我强烈建议熟悉theano.tensorpymc3.math操作,因为有时必须使用它们来正确操作随机变量,并且通常应该能够得到更有效的代码。

1
太好了,Merv!非常感谢!mu和sd接受numpy数组。在我的情况下,mu也接受列表,但sd不接受。使用numpy数组一切都很好! - P. Rinter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接