如何获取列名,即使它在 Rcpp 中为 NULL?
How to get column names even if it is NULL in Rcpp?
我想获取矩阵的列名以设置另一个矩阵,但如果矩阵没有列名(或设置为 NULL),则以下代码会使我的 R 会话崩溃。
CharacterVector cn = colnames(x);
下面的代码是我获取矩阵列名的方法,即使它没有。
#include <Rcpp.h>
using namespace Rcpp;
// Get column names or empty
// [[Rcpp::export]]
CharacterVector get_colnames(const NumericMatrix &x) {
CharacterVector cn;
SEXP cnm = colnames(x);
if (!Rf_isNull(cnm)) cn = cnm;
return(cn);
}
有没有更优雅的方式?
几点注意事项:
- 矩阵并不总是设置
colnames()
或 rownames()
。
- 如果设置了一个,则对象具有
dimnames
的属性。
- 可以通过 C API 为 R 检查值是否存在。
- 例如
Rf_isNull()
.
- 另一种存在性检查是验证
dimnames
是否是对象属性的一部分。
- 从那里,检查
dimnames
中的条目是否为空。
让我们首先创建一个矩阵 没有 名称,然后创建一个 有 名称来验证这些第一点。最后,我们将介绍一个更详细的函数版本,该函数尝试解析没有 列名称的矩阵 。
矩阵构造
因此,传统的矩阵构造为:
x_no_names = matrix(1:4, nrow = 2)
x_no_names
#> [,1] [,2]
#> [1,] 1 3
#> [2,] 2 4
colnames(x_no_names)
#> NULL
rownames(x_no_names)
#> NULL
attributes(x_no_names)
#> $dim
#> [1] 2 2
因此,没有 dimnames
创建的矩阵 没有 列或行名称。
如果我们将列名或行名分配给属性会怎样?
# Create a matrix with names
x_named = x_no_names
colnames(x_named) = c("Col 1", "Col 2")
rownames(x_named) = c("Row 1", "Row 2")
# View attributes
attributes(x_named)
#> $dim
#> [1] 2 2
#>
#> $dimnames
#> $dimnames[[1]]
#> [1] "Row 1" "Row 2"
#>
#> $dimnames[[2]]
#> [1] "Col 1" "Col 2"
# View matrix object
x_named
#> Col 1 Col 2
#> Row 1 1 3
#> Row 2 2 4
注意:matrix
对象现在有一个 dimnames
属性。
在 C++ 中实现检查
根据我们对matrix
结构的理解,我们可以检查:
dimnames
是否作为属性存在于矩阵中?
dimnames
中的第二个条目不是NULL
吗?
注意:这种方法会使原来的函数更加冗长。权衡是函数将避免必须使用 SEXP
return 类型。
#include <Rcpp.h>
// Get column names or empty
// [[Rcpp::export]]
Rcpp::CharacterVector get_colnames(const Rcpp::NumericMatrix &x) {
// Construct a character vector
Rcpp::CharacterVector cn;
// Create a numerical index for each column
Rcpp::IntegerVector a = Rcpp::seq_len(x.ncol());
// Coerce it to a character
Rcpp::CharacterVector b = Rcpp::as<Rcpp::CharacterVector>(a);
// Assign to character vector
cn = b;
if(x.hasAttribute("dimnames")) {
Rcpp::List dimnames = x.attr( "dimnames" ) ;
if(dimnames.size() != 2) {
Rcpp::stop("`dimnames` attribute must have a size of 2 instead of %s.", dimnames.size());
}
// Verify column names exist by checking for NULL
if(!Rf_isNull(dimnames[1]) ) {
// Retrieve colnames and assign to cn.
cn = dimnames[1];
} else {
// Assign to the matrix
colnames(x) = cn;
}
}
return(cn);
}
测试 C++ 变体
调用函数现在会给出:
get_colnames(x_no_names)
#> [1] "1" "2"
get_colnames(x_named)
#> [1] "Col 1" "Col 2"
第一个表示我们正在使用生成的索引,而第二个表示正在检索值。
我开始这个然后分心了。 @coatless 覆盖了它,这只是更短。
代码
#include <Rcpp.h>
// [[Rcpp::plugins(cpp11)]]
using namespace Rcpp;
// [[Rcpp::export]]
CharacterVector getColnames(const NumericMatrix &x) {
size_t nc = x.cols();
SEXP s = x.attr("dimnames"); // could be nil or list
if (Rf_isNull(s)) { // no dimnames, need to construct names
CharacterVector res(nc);
for (size_t i=0; i<nc; i++) {
res[i] = std::string("V") + std::to_string(i);
}
return(res);
} else { // have names, return colnames part
List dn(s);
return(dn[1]);
}
}
/*** R
m <- matrix(1:9,3,3)
getColnames(m)
colnames(m) <- c("tic", "tac", "toe")
getColnames(m)
*/
输出
R> Rcpp::sourceCpp("~/git/Whosebug/55850510/answer.cpp")
R> m <- matrix(1:9,3,3)
R> getColnames(m)
[1] "V0" "V1" "V2"
R> colnames(m) <- c("tic", "tac", "toe")
R> getColnames(m)
[1] "tic" "tac" "toe"
R>
我想获取矩阵的列名以设置另一个矩阵,但如果矩阵没有列名(或设置为 NULL),则以下代码会使我的 R 会话崩溃。
CharacterVector cn = colnames(x);
下面的代码是我获取矩阵列名的方法,即使它没有。
#include <Rcpp.h>
using namespace Rcpp;
// Get column names or empty
// [[Rcpp::export]]
CharacterVector get_colnames(const NumericMatrix &x) {
CharacterVector cn;
SEXP cnm = colnames(x);
if (!Rf_isNull(cnm)) cn = cnm;
return(cn);
}
有没有更优雅的方式?
几点注意事项:
- 矩阵并不总是设置
colnames()
或rownames()
。- 如果设置了一个,则对象具有
dimnames
的属性。
- 如果设置了一个,则对象具有
- 可以通过 C API 为 R 检查值是否存在。
- 例如
Rf_isNull()
.
- 例如
- 另一种存在性检查是验证
dimnames
是否是对象属性的一部分。- 从那里,检查
dimnames
中的条目是否为空。
- 从那里,检查
让我们首先创建一个矩阵 没有 名称,然后创建一个 有 名称来验证这些第一点。最后,我们将介绍一个更详细的函数版本,该函数尝试解析没有 列名称的矩阵 。
矩阵构造
因此,传统的矩阵构造为:
x_no_names = matrix(1:4, nrow = 2)
x_no_names
#> [,1] [,2]
#> [1,] 1 3
#> [2,] 2 4
colnames(x_no_names)
#> NULL
rownames(x_no_names)
#> NULL
attributes(x_no_names)
#> $dim
#> [1] 2 2
因此,没有 dimnames
创建的矩阵 没有 列或行名称。
如果我们将列名或行名分配给属性会怎样?
# Create a matrix with names
x_named = x_no_names
colnames(x_named) = c("Col 1", "Col 2")
rownames(x_named) = c("Row 1", "Row 2")
# View attributes
attributes(x_named)
#> $dim
#> [1] 2 2
#>
#> $dimnames
#> $dimnames[[1]]
#> [1] "Row 1" "Row 2"
#>
#> $dimnames[[2]]
#> [1] "Col 1" "Col 2"
# View matrix object
x_named
#> Col 1 Col 2
#> Row 1 1 3
#> Row 2 2 4
注意:matrix
对象现在有一个 dimnames
属性。
在 C++ 中实现检查
根据我们对matrix
结构的理解,我们可以检查:
dimnames
是否作为属性存在于矩阵中?dimnames
中的第二个条目不是NULL
吗?
注意:这种方法会使原来的函数更加冗长。权衡是函数将避免必须使用 SEXP
return 类型。
#include <Rcpp.h>
// Get column names or empty
// [[Rcpp::export]]
Rcpp::CharacterVector get_colnames(const Rcpp::NumericMatrix &x) {
// Construct a character vector
Rcpp::CharacterVector cn;
// Create a numerical index for each column
Rcpp::IntegerVector a = Rcpp::seq_len(x.ncol());
// Coerce it to a character
Rcpp::CharacterVector b = Rcpp::as<Rcpp::CharacterVector>(a);
// Assign to character vector
cn = b;
if(x.hasAttribute("dimnames")) {
Rcpp::List dimnames = x.attr( "dimnames" ) ;
if(dimnames.size() != 2) {
Rcpp::stop("`dimnames` attribute must have a size of 2 instead of %s.", dimnames.size());
}
// Verify column names exist by checking for NULL
if(!Rf_isNull(dimnames[1]) ) {
// Retrieve colnames and assign to cn.
cn = dimnames[1];
} else {
// Assign to the matrix
colnames(x) = cn;
}
}
return(cn);
}
测试 C++ 变体
调用函数现在会给出:
get_colnames(x_no_names)
#> [1] "1" "2"
get_colnames(x_named)
#> [1] "Col 1" "Col 2"
第一个表示我们正在使用生成的索引,而第二个表示正在检索值。
我开始这个然后分心了。 @coatless 覆盖了它,这只是更短。
代码
#include <Rcpp.h>
// [[Rcpp::plugins(cpp11)]]
using namespace Rcpp;
// [[Rcpp::export]]
CharacterVector getColnames(const NumericMatrix &x) {
size_t nc = x.cols();
SEXP s = x.attr("dimnames"); // could be nil or list
if (Rf_isNull(s)) { // no dimnames, need to construct names
CharacterVector res(nc);
for (size_t i=0; i<nc; i++) {
res[i] = std::string("V") + std::to_string(i);
}
return(res);
} else { // have names, return colnames part
List dn(s);
return(dn[1]);
}
}
/*** R
m <- matrix(1:9,3,3)
getColnames(m)
colnames(m) <- c("tic", "tac", "toe")
getColnames(m)
*/
输出
R> Rcpp::sourceCpp("~/git/Whosebug/55850510/answer.cpp")
R> m <- matrix(1:9,3,3)
R> getColnames(m)
[1] "V0" "V1" "V2"
R> colnames(m) <- c("tic", "tac", "toe")
R> getColnames(m)
[1] "tic" "tac" "toe"
R>