使用Rccp重写循环



我是Rcpp的新手用户。我想固定我的for loop,它使用r环境中的几个实体,并通过迭代更新两个向量。问题是这是我第一次面对cc++,所以我不知道如何用inline包编写rcpp。这是我想要重写的可复制循环。

rsi <- c(NaN, 0, 0, 9.2, 28, 11, 9, 8, 38, 27, 62, 57,59,67, 76, 68, 69, 49)
L <- 2
o <- 2
T_min <-100
T_m <- 0
# Predefine two vectors for results to be written in
rsi_u <- rep(0, length(rsi))
rsi_d <- rep(0, length(rsi))
# Set range of for loop to be apllied on
st <- L + 1 # L and o is some param fron environment
en <- length(rsi) - o - 2
for (i in st:en) {
k <- i - o + 1
k1 <- i - L + 1
if (sum(rsi_u[k:i]) == 0 & sum(rsi_d[k:i]) == 0) {
if (min(rsi[k1:i]) == rsi[i] & rsi[i] < T_min) {
rsi_d[i] <- 1
}
if (max(rsi[k1:i]) == rsi[i] & rsi[i] > T_m) {
rsi_u[i] <- 1
}
}
}

因此,正如你所看到的,有一个检查第一条件的循环

if (sum(rsi_u[k:i]) == 0 & sum(rsi_d[k:i]) == 0) 

然后检查另外两个条件。如果条件之一是T,则它将1L写入两个预定义向量之一的第i个元素。此外,每次迭代都依赖于先前迭代的结果。

该循环的结果是两个向量:rsi_ursi_d

为了加快这个循环,我决定用rccpinline重写它。这就是我最终得到的:

library("Rcpp")
library("inline")
loop_c <- cxxfunction(signature(k = "numeric", L = "numeric", 
en = "numeric", rsi = "numeric", o = "numeric", T_min = "numeric", T_m  ="numeric"), 
plugin = "Rcpp", body = "
for (int i = L + 1; i <= en; i++) {
k = i - o + 1
k1 = i - L + 1
if (accumulate(rsi_u.k(), rsi_u.i(), 0)=0 &&
accumulate(rsi_d.k(), rsi_d.i(), 0)=0) {
if (min_element(rsi.k1(), rsi.i()) = rsi.i() && rsi.i < T_min) {
rsi_u.i = 1
}
if (max_element(rsi.k1(), rsi.i()) = rsi.i() && rsi.i > T_m) {
rsi_d.i = 1
}
}
}
return ?")

所以问题来了:

  1. 如何以具有2列和length(rsi)行的data.framematrix的形式返回到R environment向量rsi_ursi_d
  2. 这个循环可以用其他工具加速吗?我试着申请家庭,但速度较慢

如何以data.frame或具有2列和长度(rsi(行的矩阵的形式返回R环境向量rsi_u和rsi_d

不完全确定您想要实现什么,但无论如何,您都可以使用Rcpp和糖函数summaxmin在C++中重写代码。该代码与R等效代码非常相似。需要注意的一些重要事项是,C++是强类型的,这意味着22.0是不同的数字(相当于R中的22L(,向量是0索引的,而不是R中的1索引(例如:NumericVector F(3)的第一个元素是0,最后一个元素是2,在R中是1和3(。这可能会导致一些混乱,但剩余的代码是相同的。

#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
List fun(NumericVector rsi,
double T_min, double T_m,
R_xlen_t L, R_xlen_t o) {
R_xlen_t n = rsi.size(),
st = L + 1,
en = n - o  - 2;
NumericVector rsi_u(n), rsi_d(n);
// Note subsets are 0 indexed, so add -1 to indices
for(R_xlen_t i = st - 1; i < en; i++) {
R_xlen_t k = i - o + 1;
R_xlen_t k1 = i - L + 1;
Range sr(k, i), mr(k1, i);
//LogicalVector rsub = sum(rsi_u[sr]) == 0, rsdb = sum(rsi_d[sr]) == 0;
if(sum(rsi_u[sr]) == 0 && sum(rsi_d[sr]) == 0){
if(min(rsi[mr]) == rsi[i] && rsi[i] < T_min){
rsi_d[i] = 1.0;
}
if(max(rsi[mr]) == rsi[i] && rsi[i] > T_m){
rsi_u[i] = 1.0;
}
}
}
return DataFrame::create(Named("rsi_d") = rsi_d, Named("rsi_u") = rsi_u);
}

附带说明一下,inline包现在每天都是完全多余的。大部分(如果不是全部的话(功能都封装在Rcpp::cppFunctionRcpp::sourceCpp功能中。可以使用以下任一命令导入上面的代码:

library(Rcpp)
cppFunction(
'
// copy code to here. Note the single " ' "! Needed if there are double quotes in your C++ code
')
# Alternative
sourceCpp(
file = # Insert file path to file with code here
# Alt:
# code = '
# // copy code to here. Note the single " ' "! Needed if there are double quotes in your C++ code
# '
)

就是这样。

这个循环可以用其他工具加速吗?我试着申请家庭,但速度较慢

对于问题的这一部分,您应该关注的主要想法是向量化您的代码。在您的示例中,这不是立即可能的,因为您正在重写循环中条件中使用的部分rsi_drsi_u向量。使用*apply相当于使用for-loop,不会显著提高性能。

最新更新