减少状态模型 glm 的多重处理

Reduce multiprocessing for statsmodels glm

我目前正在为我们需要逻辑回归的业务流程之一进行概念验证。我一直在使用 statsmodels glm 对我们的数据集进行分类(按照下面的代码)。我们的数据集包含约 1000 万行和大约 80 个特征(其中近 70 多个是虚拟变量,例如基于定义的分类变量的“1”或“0”)。使用较小的数据集,glm 工作正常,但是如果我 运行 它针对完整数据集,python 会抛出错误 "cannot allocate memory".

glmmodel = smf.glm(formula, data, family=sm.families.Binomial())
glmresult = glmmodel.fit()
resultstring = glmresult.summary().as_csv()

这让我想到这可能是由于 statsmodels 被设计为利用所有可用的 cpu 内核,并且下面的每个子进程都会将数据集的副本创建到 RAM 中(如果我有错误请纠正我我弄错了)。现在的问题是 glm 是否有办法只使用最少数量的内核?我不喜欢性能,只是希望能够 运行 glm 针对完整数据集。

作为参考,下面是机器配置,如果需要还可以提供更多信息。

CPU: 10 cores
RAM: 40 GB (usable/free ~25GB as there are other processes running on the 
same machine)
swap: 16 GB
dataset size: 1.4 GB (based on Panda's DataFrame.info(memory_usage='deep')

GLM 仅通过线性代数库使用多处理

以下从https://github.com/statsmodels/statsmodels/issues/2914复制我的FAQ问题描述 它包含一些指向出现此问题的其他问题的链接。

(引用:)

Statsmodels 在我们控制的几个地方使用 joblib 进行并行处理。目前主要用于bootstrap,并没有直接在模型中使用。

但是,numpy/scipy 中的一些底层 Blas/Lapack 库也使用多核。这对于具有大型数组的线性代数可能是有效的,但它也会减慢操作速度,尤其是当我们想要在更高级别上使用并行处理时。

我们如何限制线性代数库使用的内核数量?

这取决于使用哪个线性代数库。查看邮件列表线程 https://groups.google.com/d/msg/pystatsmodels/Lz9-In0pgPk/BtcYsj_ABQAJ

openblas:尝试设置环境变量OMP_NUM_THREADS=1

在 OSX 上加速,设置 VECLIB_MAXIMUM_THREADS

水蟒中的 mkl:

import mkl
mkl.set_num_threads(1)

这是因为 Statsmodels 在估计 GLM 时使用 IRLS,而 IRLS 过程利用其 WLS 回归例程,该例程再次使用 QR 分解。 QR 分解是直接在 X 上完成的,你的 X 有 1000 万行,80 列,结果给内存带来了很大压力 CPU.

这是来自 statsmodels 的源代码:

        if method == 'pinv':
            pinv_wexog = np.linalg.pinv(self.wexog)
            params = pinv_wexog.dot(self.wendog)
        elif method == 'qr':
            Q, R = np.linalg.qr(self.wexog)
            params = np.linalg.solve(R, np.dot(Q.T, self.wendog))
        else:
        params, _, _, _ = np.linalg.lstsq(self.wexog, self.wendog,