如何有效地将数字矢量列表组合到一个大数字向量中
How to effectively combine a list of NumericVectors into one large NumericVector?
我编写了以下编译的RCPP代码,但速度不像预期的那样快。
// [[Rcpp::export]]
NumericVector combine_list_to_vec (const Rcpp::List& list)
{
int list_size = list.size();
int large_vec_size = 0;
IntegerVector start_index(list_size);
IntegerVector end_index(list_size);
for (int ii = 0; ii < list_size; ii++)
{
NumericVector vec = list[ii];
start_index[ii] = large_vec_size;
large_vec_size += vec.size();
end_index[ii] = large_vec_size - 1;
}
NumericVector large_vec(large_vec_size); // Creating object after getting its size
for (int ii = 0; ii < list_size; ii++)
{
int current_start_index = start_index[ii];
NumericVector vec = list[ii];
for (int jj = 0; jj < vec.size(); jj++)
{
large_vec[jj + current_start_index] = vec[jj];
}
}
return large_vec;
}
输入变量"列表"包含一堆数字向量,我想将它们组合成一个大型数字,并使用'...尾巴-tail ...'结构。start_index和end_index变量用于促进复制。
Microbenchmark测试提供了以下特定示例的信息:
x=list();
x[[1]]=runif(1E6); x[[2]]=runif(1E6);
x[[3]]=runif(1E6); x[[4]]=runif(1E6);
x[[5]]=runif(1E6); x[[6]]=runif(1E6);
x[[7]]=runif(1E6); x[[8]]=runif(1E6);
x[[9]]=runif(1E6); x[[10]]=runif(1E6);
microbenchmark(combine_list_to_vec(x) -> y)
# Unit: milliseconds
expr min lq mean median uq max neval
# y <- combine_list_to_vec(x) 84.166964 84.587516 89.9520601 84.728212 84.871673 349.33234 100
我尝试的另一种方法是调用外部R函数do.call(c,x)
:
// [[Rcpp::export]]
List combine_list_to_vec (const Rcpp::List& list)
{
int list_size = list.size();
int large_vec_size = 0;
IntegerVector start_index(list_size);
IntegerVector end_index(list_size);
for (int ii = 0; ii < list_size; ii++)
{
NumericVector vec = list[ii];
start_index[ii] = large_vec_size;
large_vec_size += vec.size();
end_index[ii] = large_vec_size - 1;
}
NumericVector large_vec = internal::convert_using_rfunction(list, "sub_do_call");
List rtn = List::create(large_vec, start_index, end_index);
return rtn;
}
// The following codes exist as R codes instead of Rcpp
sub_do_call <- function (x)
{
return (do.call(c, x));
}
速度比以前的代码快几乎快4倍。有什么方法可以通过使用RCPP和/或RCPPARMADILLO中的指针或其他工具加速组合操作,或者简单地使用RCPP中的Codal(C,X)而不是外部调用它?谢谢。
如果我正确理解,您基本上问:"如何在Rcpp
中写base::unlist
?"而且,由于base::unlist
是.Internal
函数(具有C实现),因此您不太可能使用Rcpp
。
但是,无论如何,让我们尝试一下。这是我使用的实现与您类似的实现,但是当我们使用std::copy
而不是在每次迭代中重新索引时,应该更便宜:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector combine(const List& list)
{
std::size_t n = list.size();
// Figure out the length of the output vector
std::size_t total_length = 0;
for (std::size_t i = 0; i < n; ++i)
total_length += Rf_length(list[i]);
// Allocate the vector
NumericVector output = no_init(total_length);
// Loop and fill
std::size_t index = 0;
for (std::size_t i = 0; i < n; ++i)
{
NumericVector el = list[i];
std::copy(el.begin(), el.end(), output.begin() + index);
// Update the index
index += el.size();
}
return output;
}
/*** R
library(microbenchmark)
x <- replicate(10, runif(1E6), simplify = FALSE)
identical(unlist(x), combine(x))
microbenchmark(
unlist(x),
combine(x)
)
*/
运行此代码给我:
> Rcpp::sourceCpp('C:/Users/Kevin/scratch/combine.cpp')
> library(microbenchmark)
> x <- replicate(10, runif(1E6), simplify = FALSE)
> identical(unlist(x), combine(x))
[1] TRUE
> microbenchmark(
+ unlist(x),
+ combine(x)
+ )
Unit: milliseconds
expr min lq mean median uq max neval
unlist(x) 21.89620 22.43381 29.20832 23.14454 35.32135 68.09562 100
combine(x) 20.96225 21.55827 28.13269 22.08985 24.13403 51.68660 100
因此,有效地相同。我们仅仅因为没有任何类型的检查而获得了很小的时间(这意味着如果我们没有仅包含数字向量的列表,则该代码会爆炸),但至少应该说明我们真的可以说明我们真的可以说明'在这里做得更好。
(我想唯一的例外是巨大向量,在这里并行处理可能会有所帮助)
相关文章:
- 如何(从固定列表中)选择一个数字序列,该序列将与目标数字相加
- 如何获取一个数字的前3位
- 我想做一个彼此不同但重复出现的数字
- 如何检查一个c++字符串中有多少相同的字符/数字
- 为什么有时我输入一个整数,程序将第一个输入的数字打印成十进制数?
- 将向量之间的数字放在另一个向量之间<vector>>如果两个数字的差值为 1
- CIN 仅在输入非数字值时跳过下一个 CIN
- 以C++输出一个数字三角形
- 形成一个斐波那契三角形,使得每个数字是上面左对角线或右对角线上两个数字的总和
- 为什么当我输入一个被接受的数字时,我的 do-while 循环没有中断?
- 一个C++程序,用于在输入位数时输出具有特定位数的 .txt 文件中的所有数字
- 在C++中编程,将 3 个数字发送到一个函数,然后计算这 3 个数字的平均函数
- 在使用堆栈为下一个最大数字编写代码时面临 SIGSEGV(分段错误)
- 找到 x^n 的所有组合,并检查它们的总和是否等于一个不包括相同数字的数字
- 是否有一个 std::set 函数来确定不超过数字 x 的最大元素?
- 将数字提高到一个巨大的指数
- 反转一个数字程序不起作用,为什么?
- 使用带有一个参数函数的递归找到数字的平方
- 为什么当我输入一个大数字时,输出会一遍又一遍地重复?
- 为什么断点显示数组的第二个值是一个大数字?额外学分工作