我试图采取一个Rcpp::CharacterMatrix并将每一行转换为自己的元素Rcpp::List.
但是,我编写的函数有一个奇怪的行为,其中列表的每个条目对应于矩阵的最后一行.为什么会这样?这是一些指针相关的概念吗?请解释.
功能:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
List char_expand_list(CharacterMatrix A) {
CharacterVector B(A.ncol());
List output;
for(int i=0;i<A.nrow();i++) {
for(int j=0;j<A.ncol();j++) {
B[j] = A(i,j);
}
output.push_back(B);
}
return output;
}
Run Code Online (Sandbox Code Playgroud)
测试矩阵:
这是A传递给上述函数的矩阵.
mat = structure(c("a", "b", "c", "a", "b", "c", "a", "b", "c"), .Dim = c(3L, 3L))
mat
# [,1] [,2] [,3]
# [1,] "a" "a" "a"
# [2,] "b" "b" "b"
# [3,] "c" "c" "c"
Run Code Online (Sandbox Code Playgroud)
输出:
上面的函数应该将此矩阵作为输入并返回矩阵行列表,如下所示:
char_expand_list(mat)
# [[1]]
# [1] "a" "a" "a"
#
# [[2]]
# [1] "b" "b" "b"
#
# [[3]]
# [1] "c" "c" "c"
Run Code Online (Sandbox Code Playgroud)
但相反,我得到了一些不同的东西:
char_expand_list(mat)
# [[1]]
# [1] "c" "c" "c"
#
# [[2]]
# [1] "c" "c" "c"
#
# [[3]]
# [1] "c" "c" "c"
Run Code Online (Sandbox Code Playgroud)
可以看出,输出具有最后一个元素,例如对于第一和第二列表元素重复的矩阵行"c".为什么会这样?
这里发生的事情很大程度上是Rcpp对象如何工作的结果.特别是,CharacterVector充当指向内存位置的指针.通过在for循环外定义此内存位置,结果是"全局"指针.也就是说,当B在循环中发生更新时,随后更新B已经方便地存储在其中的所有变体Rcpp::List.因此,"c"整个列表中的重复行.
有了这个说法,使用任何数据类型是一个非常非常非常糟糕的主意,因为你最终会在不断扩展的对象中来回复制.当Rcpp数据类型隐藏控制R对象的底层时,将发生复制,该对象必须重新创建.因此,您应该尝试以下方法之一:.push_back()RcppSEXP
Rcpp::CharacterVector创建的位置在第一个for循环内并预分配Rcpp::List空间.std::list与std::vector<T>类型T(即std::string)Rcpp::wrap(x)返回正确的对象或修改函数返回类型Rcpp::List来std::list<std::vector<T> >.Rcpp::List空间和使用std::vector<T>类型T(即std::string).Rcpp::List空间并创建一个clone()Rcpp对象.在这里,我们通过将声明移动B到第一个循环中来重新排列函数,预分配列表空间,并正常访问输出列表.
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
Rcpp::List char_expand_list_rearrange(Rcpp::CharacterMatrix A) {
Rcpp::List output(A.nrow());
for(int i = 0; i < A.nrow(); i++) {
Rcpp::CharacterVector B(A.ncol());
for(int j = 0; j < A.ncol(); j++) {
B[j] = A(i, j);
}
output[i] = B;
}
return output;
}
Run Code Online (Sandbox Code Playgroud)
在这里,我们删除Rcpp::CharacterVector赞成std::vector<std::string>和取代Rcpp::List的std::list<std::vector<std::string> >.最后,我们将标准对象转换为Rcpp::Listvia Rcpp::wrap().
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
Rcpp::List char_expand_std_to_list(Rcpp::CharacterMatrix A) {
std::vector<std::string> B(A.ncol());
std::list<std::vector<std::string> > o;
for(int i = 0 ;i < A.nrow(); i++) {
for(int j = 0; j < A.ncol(); j++) {
B[j] = A(i, j);
}
o.push_back(B);
}
return Rcpp::wrap(o);
}
Run Code Online (Sandbox Code Playgroud)
赠送:
mat = structure(c("a", "b", "c", "a", "b", "c", "a", "b", "c"), .Dim = c(3L, 3L))
char_expand_std_to_list(mat)
# [[1]]
# [1] "a" "a" "a"
#
# [[2]]
# [1] "b" "b" "b"
#
# [[3]]
# [1] "c" "c" "c"
Run Code Online (Sandbox Code Playgroud)
或者,你可以保持Rcpp::List,但只是提前声明它预期的大小,仍然使用一个std::vector<T>元素.
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
Rcpp::List char_expand_list_vec(Rcpp::CharacterMatrix A) {
std::vector<std::string> B(A.ncol());
Rcpp::List o(A.nrow());
for(int i = 0; i < A.nrow(); i++) {
for(int j = 0; j < A.ncol(); j++) {
B[j] = A(i, j);
}
o[i] = B;
}
return o;
}
Run Code Online (Sandbox Code Playgroud)
最后,在为列表预定义空间的情况下,在每次迭代时都会显式克隆数据.
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
Rcpp::List char_expand_list_clone(Rcpp::CharacterMatrix A) {
Rcpp::CharacterVector B(A.ncol());
Rcpp::List output(A.nrow());
for(int i = 0; i < A.nrow(); i++) {
for(int j = 0; j < A.ncol(); j++) {
B[j] = A(i, j);
}
output[i] = clone(B);
}
return output;
}
Run Code Online (Sandbox Code Playgroud)
基准测试结果表明,具有重新布置和预分配空间的选项1表现最佳.亚军第二是选项4,它包括克隆每个向量,然后将其保存到Rcpp::List.
library("microbenchmark")
library("ggplot2")
mat = structure(c("a", "b", "c", "a", "b", "c", "a", "b", "c"), .Dim = c(3L, 3L))
micro_mat_to_list =
microbenchmark(char_expand_list_rearrange(mat),
char_expand_std_to_list(mat),
char_expand_list_vec(mat),
char_expand_list_clone(mat))
micro_mat_to_list
# Unit: microseconds
# expr min lq mean median uq max neval
# char_expand_list_rearrange(mat) 1.501 1.9255 3.22054 2.1965 4.8445 6.797 100
# char_expand_std_to_list(mat) 2.869 3.2035 4.90108 3.7740 6.4415 27.627 100
# char_expand_list_vec(mat) 1.948 2.2335 3.83939 2.7130 5.2585 24.814 100
# char_expand_list_clone(mat) 1.562 1.9225 3.60184 2.2370 4.8435 33.965 100
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
858 次 |
| 最近记录: |