运行 稀疏设计矩阵上带有 rpy2 的 glmnet?

Running glmnet with rpy2 on sparse design matrix?

我有一个 python 片段,它对 运行 GLMNET 在 np.array X 和 y 上工作得很好。但是,当 X 是来自 scipy 的列稀疏矩阵时,代码失败,因为 rpy2 无法转换 X。我犯了一个明显的错误吗?

一个 MCVE 是:

import numpy as np
from scipy import sparse
from rpy2 import robjects
import rpy2.robjects.packages as rpackages
from rpy2.robjects import numpy2ri
from rpy2.robjects import pandas2ri

if __name__ == "__main__":
    X = sparse.rand(5, 20, density=0.1)
    y = np.random.randn(5)
    numpy2ri.activate()
    pandas2ri.activate()

    utils = rpackages.importr('utils')
    utils.chooseCRANmirror(ind=1) 
    if not rpackages.isinstalled('glmnet'):
        utils.install_packages("glmnet")
    glmnet = rpackages.importr('glmnet')

    glmnet = robjects.r['glmnet']
    glmnet_fit = glmnet(X, y, intercept=False, standardize=False)

当我 运行 它时,我得到一个 NotImplementedError:

Conversion 'py2ri' not defined for objects of type '<class 'scipy.sparse.csc.csc_matrix'>'

我可以用不同的方式提供 X 吗?如果 rpy2 无法处理稀疏矩阵,我会感到惊讶。

确实没有转换器 Python -> R 适用于 rpy2 中包含的对象类型。您的 Python 对象不是常规数组,而是您注意到的稀疏矩阵(具体来说是 scipy.sparse.csc.csc_matrix),作为 numpy 可用的数字扩展之一实现。由于 numpy 本身甚至不需要使用 rpy2,因此对 numpy 扩展的支持相当稀疏,但 pandas 是一个明显的例外,因为数据表无处不在。

您可能希望在 R 包 Matrix (https://stat.ethz.ch/R-manual/R-devel/library/Matrix/html/dgCMatrix-class.html) 中编写自己的从 css_matrixgcCMatrix 的转换器,因为包 glmnet 出现能够处理它们。

编写自定义转换器将需要如何将 Python 对象的内容映射或复制到其选择的 R 对应对象,但是完成后将代码插入 rpy2 应该很容易: https://rpy2.github.io/doc/v2.9.x/html/generated_rst/s4class.html#custom-conversion

考虑在 rpy2 问题跟踪器上以 "feature request" 的形式提出一个问题,并报告进度和结果,希望看到这变成一个带有单元测试的拉取请求

还有一个可能有效的快速解决方案是临时保存稀疏矩阵文件。

import numpy as np
import rpy2.robjects as ro
import warnings
from rpy2.rinterface import RRuntimeWarning
import rpy2.robjects.numpy2ri as numpy2ri
from scipy.io import mmwrite
mmwrite('temp.mtx',matrix)
ro.r('X <- readMM("temp.mtx")')

不过,如果有人带有自定义转换器来避免复制到磁盘,我会非常感兴趣。

您可以使用 rpy2 创建稀疏矩阵,如下所示:

import numpy as np
import rpy2.robjects as ro
from rpy2.robjects.packages import importr
from scipy import sparse

X = sparse.rand(5, 20, density=0.1).tocoo()
r_Matrix = importr("Matrix")
r_Matrix.sparseMatrix(
    i=ro.IntVector(X.row + 1),
    j=ro.IntVector(X.col + 1),
    x=ro.FloatVector(X.data),
    dims=ro.IntVector(X.shape))