【问题标题】:Growing an R matrix inside a C loop在 C 循环中增长 R 矩阵
【发布时间】:2011-09-17 22:51:15
【问题描述】:

我有一个生成一系列数据向量的例程,一次迭代一次。我想找到一种方法来“增长”包含这些向量的列表或矩阵。我试图创建一个列表,

PROTECT( myList = allocVector( VECSXP, 1 ) )

但是有没有办法通过最后推送一个向量元素来增加列表?

另外,我不介意使用矩阵,因为我生成的向量长度相同。

【问题讨论】:

  • 我有几个 C++ 建议给你...

标签: c r matrix


【解决方案1】:

Rf_lengthgets in Rinternals.h;在builtin.c:lengthgets 中实施。返回的指针需要被保护,所以一种模式是

SEXP myList;
PROTECT_INDEX ipx;
PROTECT_WITH_INDEX(myList = allocVector( VECSXP, 1 ), &ipx);
REPROTECT(mylist = Rf_lengthgets(mylist, 100), ipx);

如果基于某些未知的停止条件来增长列表,则该方法可能类似于 R 中的方法,先进行预分配和填充,然后再进行扩展;以下是伪代码:

const int BUF_SIZE = 100;
PROTECT_INDEX ipx;
SEXP myList;
int i, someCondition = 1;

PROTECT_WITH_INDEX(myList=allocVector(VECSXP, BUF_SIZE), &ipx);
for (i = 0; some_condition; ++i) {
    if (Rf_length(myList) == i) {
        const int len = Rf_length(myList) + BUF_SIZE;
        REPROTECT(myList = Rf_lengthgets(mYlist, BUF_SIZE), &ipx);
    }
    PROTECT(result = some_calculation();
    SET_VECTOR_ELT(myList, i, result);           
    UNPROTECT(1);
    // set some_condition
}
Rf_lengthgets(myList, i); // no need to re-PROTECT; we're leaving C
UNPROTECT(1)
return myList;

这会执行myList 的深层复制,因此可能会变得昂贵,并且在某些方面,如果主要目标是评估 some_calculation,那么执行预分配和扩展操作似乎更容易,效率也不会太低在 R 循环中,调用 some_calculation 并在循环内进行赋值。

【讨论】:

  • 很有趣,谢谢。这种方法的问题在于,一旦我再次调用 C 过程,就无法“保存”可变长度。确实,我想在列表中推送的数据向量是用 Fortran 代码生成的;我可以保存它们的唯一方法是将它们推送到列表中,该列表要么在此类数据向量第一次到达时在 R 环境中创建,要么从 R 环境中读取并推送到列表的最后位置。所以也许我的问题应该是,“有没有办法将向量推到由 R 环境引入 C 的列表的最后位置”?
  • 不确定我是否明白你在说什么;我尝试添加一个示例,使用可以从 R 对象获得的有关其长度的信息。
  • 谢谢马丁。但它应该比这更简单:SEXP mylist, newElement; PROTECT( mylist = findVarInFrame( rho, install("myRList") ); // myList has length n; I want to add newElement to it and return // it back to R PROTECT( newElement = allocVector( REALSXP, 5 ) ); // push newElement in the end of myList defineVar( install("myRList"), myList, rho ) ); 与在我使用相同方法从 R 读取的矩阵中添加一行相同。
  • 我不建议这样做。您希望 C 代码的行为类似于 R 函数调用——创建和修改新对象,而不是修改现有对象。也许您想从 R 中传递当前向量,但您仍想在更改之前复制它。或者,也许您只是返回 newElement,并将其添加到 R 中的现有列表中。
【解决方案2】:

恕我直言,这是 C++ 轻松击败 C 的一个很好的例子。

在 C++ 中,您可以使用 STL 容器(例如向量)并使用 push_back() 轻松地一次插入一个元素。你从不使用mallocfree(或newdelete),你从不触摸指针。在 C 中没有办法做到这一点。

同样,您可以利用 R 和 C++ 之间的Rcpp 接口,这使得将您在 C++ 中增长的数据转移到 R 变得更加容易。

【讨论】:

  • 谢谢。但是,C++ 不是一种选择。我使用 C 代码作为 Fortran 的包装器,就像所有这些过程一样 - 实际上,我以迭代方式评估 R 对象。
  • 需要包装 Fortran 并不排除使用 C++。
  • 确实如此。但我选择不在这个特定项目上使用 c++。
猜你喜欢
  • 1970-01-01
  • 2021-05-24
  • 2012-02-21
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 2014-10-02
  • 2018-01-30
  • 2023-03-22
相关资源
最近更新 更多