R向量大小限制:“long vectors (argument 5) are not supported in .C”

13

我有一个非常大的矩阵,我正试图在一台内存充足的服务器上通过glmnet运行它。即使在非常大的数据集上,它也能正常工作,但在某个点之后,我会得到以下错误:

Error in elnet(x, ...) : long vectors (argument 5) are not supported in .C

如果我理解正确,这是由于R的限制造成的,它不能拥有长度超过INT_MAX的任何向量。这是正确的吗?是否有任何可用的解决方案,不需要完全重写glmnet?任何其他的R解释器(如Riposte等)是否解决了这个限制?

谢谢!


在你的代码中,你是否对矩阵进行了子集操作?我可能错了,但如果矩阵的元素超过360亿个,你就无法执行矩阵子集操作。在这种情况下,你必须将矩阵子集化为一个巨大的原子向量(实际上,矩阵只是带有维度属性的向量)。 - SabDeM
在我的代码中,我使用文件支持的大矩阵来避免这些问题,但是当我运行glmnet时,我必须将其作为一个R矩阵传递,就像这样:theMatrix[,] - Danny
2
嗨Danny,我的评论与问题不直接相关,但或许能帮到你。看看Michael Kane的pirls包——https://github.com/kaneplusplus/pirls。也许这个求解器可以处理长向量。 - Dmitriy Selivanov
1
问题实际上在于glmnet的底层设计,以及它使用(事实上已被弃用和不建议使用的.C())接口。Mike Kane对此进行了深入研究,pirls确实应该提供一些东西。当然,它比较小/年轻/测试不够充分,所以结果可能因人而异。 - Dirk Eddelbuettel
刚刚发现了另一个非常有前途的软件包 - https://github.com/jaredhuling/oem - Dmitriy Selivanov
2个回答

11

自版本3起,R支持长向量。长向量的索引为double。只要每个维度都足够小,可以由integer进行索引,长向量可以成为矩阵或多于2维数组的基础。无法通过.C.Fortran将长向量传递给本地代码。您收到的错误消息是因为正在通过.C传递长向量。

可以通过.Call传递长向量。因此,只要glmnet的本地代码支持长向量(64位索引)或可以修改/编译以支持它,就可以将长向量用作输入。您可以在C中手动执行此操作,还有一个名为dotCall64的新包可用于此任务。修改接口的一部分是决定何时复制参数-.C/.Fortran预防性复制,但您不希望在大型数据结构上不必要地执行此操作。

我认为更改glmnet本地代码以支持64位索引的难度取决于实际代码(我只看过但从未使用过)。将Fortran代码中的所有整数(显式或隐式32位整数)切换为64位很容易。当某些整数必须保留32位时出现问题,这将发生在从/到R代码传递的整数向量中,因为R使用32位整数(事实上,即使在长向量中也是如此)。在glmnet中传递这样的整数向量。然后修改的难度取决于原始Fortran代码的清晰程度(例如,如果它使用单独的整数变量来索引和访问整数数组的值等)。

实验性的R子集的实现,例如Riposte,将毫无帮助。


谢谢提供的信息,但是我查了一些资料发现,从.C 切换到 .Call 需要对底层的Fortran代码进行重大更改。这正是我想避免的。听起来似乎没有一个适合我的需求的解决方案。 - Danny
1
我已更新我的回复。我认为难度取决于实际的代码,因此那些与该代码一起工作过的人能够给出最好的答案。我的猜测是:经过一两天的编程,你要么完成它,要么有一个很好的估计值。当然这不应该是完全重写。 - Tomas Kalibera
1
那似乎解决了! 对我而言关键是dotCall64软件包。 直接使用.Call有点超出了我现在的时间和复杂度,但是通过dotCall64,我只需要复制.Fortran调用并添加输入变量的数据类型列表即可。 确定正确的数据类型花费了一些时间,但并不太困难。 仍然存在一些内存问题,但我想我能够解决它们。 非常感谢Tomas! - Danny

2

"长向量"的注释中有如下说明:

然而,编译后的代码通常需要相当大的改动。请注意,.C和.Fortran接口不接受长向量,因此必须使用.Call(或类似方法)。

elnet使用了.Fortran调用。您需要修改该函数以使用.Call,可能需要通过调用FORTRAN代码的C包装器来进行,并且可能需要重写和编译相关的FORTRAN代码以处理长向量。


谢谢提供的信息,但是我查了一些资料发现,从.C切换到.Call需要对底层Fortran代码进行重大更改。这正是我想要避免的。听起来似乎没有适合我需求的解决方案。 - Danny
不,如果底层代码与32位向量绑定在一起,恐怕您就无法更改了。 - James

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