问题描述
|
我正在编写一个R包,用于在C中操纵矩阵。当前,返回到R的矩阵具有行/列名称的数字。在C语言中修改对象时,我宁愿分配自己的行/列名称。
我已经在Google上搜索了大约一个小时,但是还没有找到一个好的解决方案。我找到的最接近的是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
解决方法
正如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,nam);
SET_VECTOR_ELT(dimnames,1,nam);
setAttrib(ans,R_DimNamesSymbol,dimnames);
UNPROTECT(2);
return(ans);
}
如果将该代码放在名为myMat.c
的文件中,则可以通过下面的行对其进行测试。我正在使用Ubuntu,因此如果您使用Windows,则必须将ѭ4更改为ѭ5。
R CMD SHLIB myMat.c
Rscript -e \'dyn.load(\"myMat.so\"); .Call(\"myMat\",c(\"A\",\"C\",\"G\",\"T\"))\'
,如果您对C ++而不是C持开放态度,那么Rcpp可以使此操作变得容易一些。我们只需要像在R中那样创建一个具有行和列名称的列表对象,并将其分配给矩阵对象的the7ѭ属性:
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(),plugin=\"Rcpp\")
R> fun()
ee ff
cc 42 42
dd 42 42
R>
因此,我们只剩下3或4条语句,不会在PROTECT / UNPROTECT上胡闹,也没有内存管理。,上面的说明具有指导意义。昏暗的名字是一个具有与数据集维度相同数量的元素的列表,其中每个元素对应于沿该维度的数量元素,即“ 11”。
要在C中进行设置,我建议:
PROTECT(dimnames = allocVector(VECSXP,2));
PROTECT(rownames = allocVector(STRSXP,4));
PROTECT(colnames = allocVector(STRSXP,4));
setAttrib( ?,dimnames);
然后,您必须设置相关的行名和列名元素。通常,在R中执行此操作要容易得多。
吉姆