【问题标题】:R extension in C, setting matrix row/column namesC中的R扩展,设置矩阵行/列名称
【发布时间】:2011-08-08 06:31:42
【问题描述】:

我正在编写一个在 C 中操作矩阵的 R 包。目前,返回给 R 的矩阵具有行/列名称的数字。在 C 中修改对象时,我宁愿分配自己的行/列名。

我已经用谷歌搜索了大约一个小时,但还没有找到好的解决方案。我发现最接近的是 dimnames,但我想命名每一列,而不仅仅是两个维度。矩阵变得大于 4x4,下面只是我想要做的一个小例子。

行数为 4^x,其中 X 是行名的长度

Current
     [,1] [,2] [,3] [,4]
[1,] 0.20 0.00 0.00 0.80
[2,] 0.25 0.25 0.25 0.25
[3,] 0.25 0.25 0.25 0.25
[4,] 1.00 0.00 0.00 0.00
[5,] 0.20 0.00 0.00 0.80
[6,] 0.25 0.25 0.25 0.25
[7,] 0.25 0.25 0.25 0.25
[8,] 1.00 0.00 0.00 0.00
[9,] 0.20 0.00 0.00 0.80
[10,] 0.25 0.25 0.25 0.25
[11,] 0.25 0.25 0.25 0.25
[12,] 1.00 0.00 0.00 0.00
[13,] 0.20 0.00 0.00 0.80
[14,] 0.25 0.25 0.25 0.25
[15,] 0.25 0.25 0.25 0.25
[16,] 1.00 0.00 0.00 0.00

Desired
     [A] [C] [G] [T]
 [AA] 0.20 0.00 0.00 0.80
 [AC] 0.25 0.25 0.25 0.25
 [AG] 0.25 0.25 0.25 0.25
 [AT] 1.00 0.00 0.00 0.00
 [CA] 0.20 0.00 0.00 0.80
 [CC] 0.25 0.25 0.25 0.25
 [CG] 0.25 0.25 0.25 0.25
 [CT] 1.00 0.00 0.00 0.00
 [GA] 0.20 0.00 0.00 0.80
 [GC] 0.25 0.25 0.25 0.25
 [GG] 0.25 0.25 0.25 0.25
 [GT] 1.00 0.00 0.00 0.00
 [TA] 0.20 0.00 0.00 0.80
 [TC] 0.25 0.25 0.25 0.25
 [TG] 0.25 0.25 0.25 0.25
 [TT] 1.00 0.00 0.00 0.00

【问题讨论】:

  • dimnames 确实为每一行和每一列命名,粗略看一下 ?dimnames 将显示 dimnames(mat)

标签: c r matrix


【解决方案1】:

上面的注释具有指导意义。 dimnames 是一个列表,其元素数量与数据集的维度相同,其中每个元素对应于该维度上的数量元素,即list(c('a','c','g','t'), c('a','c','g','t'))

要在 C 中设置,我建议:

PROTECT(dimnames = allocVector(VECSXP, 2));
PROTECT(rownames = allocVector(STRSXP, 4));
PROTECT(colnames = allocVector(STRSXP, 4));
setAttrib( ? , R_DimNamesSymbol, dimnames);

然后您必须设置相关的 rowname 和 colname 元素。一般来说,这些东西在 R 中要容易得多

吉姆

【讨论】:

  • 在调用setAttrib之前需要设置dimnames的元素。 @Nick:我也建议在 R 中这样做。
  • Jim,它也需要是 UNPROTECTED(4)。我试过了,它似乎没有用。不过我会继续努力的
  • 您还需要至少以下内容,但它仍然无法正常工作... SET_STRING_ELT(rownames, 0, mkChar("A")); SET_VECTOR_ELT(dimnames, 0, rownames); SET_VECTOR_ELT(dimnames, 1, colnames);
【解决方案2】:

正如 Jim 所说,这在 R 中要容易得多。我通过 nam 参数将名称传递给 C 函数。

#include <Rinternals.h>
SEXP myMat(SEXP nam) {
  /*PrintValue(nam);*/
  SEXP ans, dimnames;
  PROTECT(ans = allocMatrix(REALSXP, length(nam), length(nam)));
  PROTECT(dimnames = allocVector(VECSXP, 2));
  SET_VECTOR_ELT(dimnames, 0, nam);
  SET_VECTOR_ELT(dimnames, 1, nam);
  setAttrib(ans, R_DimNamesSymbol, dimnames);
  UNPROTECT(2);
  return(ans);
}

如果您将该代码放在名为myMat.c 的文件中,您可以通过下面的行对其进行测试。我使用的是 Ubuntu,因此如果您使用的是 Windows,则必须将 myMat.so 更改为 myMat.dll

R CMD SHLIB myMat.c
Rscript -e 'dyn.load("myMat.so"); .Call("myMat", c("A","C","G","T"))'

【讨论】:

  • 嗯,问题在于将字符串放入 SEXP 对象中。 PROTECT(colnames = allocVector(VECSXP, 4));保护(A = NEW_CHARACTER(1)); SET_STRING_ELT(A, 0, mkChar("A")); SET_VECTOR_ELT(行名,0,A); SET_VECTOR_ELT(行名,1,A); SET_VECTOR_ELT(行名, 2, A); SET_VECTOR_ELT(rownames, 3, A);
  • 您的意思是说“将“myMat.so”更改为“myMat.dll”吗?目前,它的读取方式似乎您指的是 myMat.c 作为要更改为 myMat.dll 的东西。
【解决方案3】:

如果您对 C++ 而非 C 持开放态度,那么 Rcpp 可以使这更容易一些。我们只需像在 R 中一样创建一个包含行名和列名的列表对象,并将其分配给矩阵对象的 dimnames 属性:

R> library(inline)                         # to compile, link, load the code here
R> src <- '
+   Rcpp::NumericMatrix x(2,2);
+   x.fill(42);                           // or more interesting values
+   // C++0x can assign a set of values to a vector, but we use older standard
+   Rcpp::CharacterVector rows(2); rows[0] = "aa"; rows[1] = "bb";
+   Rcpp::CharacterVector cols(2); cols[0] = "AA"; cols[1] = "BB";
+   // now create an object "dimnms" as a list with rows and cols
+   Rcpp::List dimnms = Rcpp::List::create(rows, cols);
+   // and assign it
+   x.attr("dimnames") = dimnms;
+   return(x);
+ '
R> fun <- cxxfunction(signature(), body=src, plugin="Rcpp")
R> fun()
   AA BB
aa 42 42
bb 42 42
R> 

列名和行名的实际分配是如此手动......因为当前的 C++ 标准不允许在初始化时直接分配向量,但这会改变。

编辑:我刚刚意识到我当然可以在行和列名上使用静态create() 方法,这使得这更容易和更短

R> src <- '
+   Rcpp::NumericMatrix x(2,2);
+   x.fill(42);                           // or more interesting values
+   Rcpp::List dimnms =                   // two vec. with static names
+       Rcpp::List::create(Rcpp::CharacterVector::create("cc", "dd"),
+                          Rcpp::CharacterVector::create("ee", "ff"));
+   // and assign it
+   x.attr("dimnames") = dimnms;
+   return(x);
+ '
R> fun <- cxxfunction(signature(), body=src, plugin="Rcpp")
R> fun()
   ee ff
cc 42 42
dd 42 42
R> 

所以我们只需要三到四个语句,无需使用 PROTECT / UNPROTECT 进行胡闹,也无需内存管理。

【讨论】:

  • 感谢您的建议,但不幸的是我仅限于 C.
  • 并非如此,因为每个通过 gcc 具有 C 的 R 安装也通过 g++ 具有 C++,并且目标代码可以互操作。
  • 是否还有.attr("rownames").attr("colnames").attr("names"),以防只想指定列名或行名?在文档中哪里可以找到这些信息?
  • 是的,正如您在 R 源代码或设置这些东西的包的源代码中看到的那样。
猜你喜欢
  • 2020-07-27
  • 1970-01-01
  • 1970-01-01
  • 2015-03-27
  • 1970-01-01
  • 2018-08-04
  • 2020-07-14
  • 2017-10-31
  • 1970-01-01
相关资源
最近更新 更多