I am trying to adapt an R script that I wrote to perform several tasks in a for-loop. The for-loop run over thousands of items, for about 900 times, therefore I would like to optimise my code at the best. I decided to go for c++ via Rcpp. Here it is my code:
cppFunction('
Rcpp::DataFrame FasterFunction(StringVector path_data, IntegerVector ID_vector, const DataFrame& DF1,
DataFrame DF2, int time1, int time2, int start_time) {
Function read_t("fread");
Function subset("[.data.frame");
Function mergeDFs("merge");
const int& TimeVal = (time1 + time2 - (2 * start_time));
for(int i = 0; i < ID_vector.size(); ++i) {
int ID = ID_vector[i];
//Define path to file
StringVector tmp_path_data = path_data;
tmp_path_data.insert(1, "/prefix_");
tmp_path_data.insert(2, std::to_string(ID));
tmp_path_data.insert(3, ".txt");
Rcpp::String res = collapse(tmp_path_data);
//Read file as DataFrame
Rcpp::DataFrame data_df = read_t(Named("file")=res);
//Extract column "name1" from DataFrame "data_df"
Rcpp::NumericVector name1_list = as<NumericVector>(data_df["name1"]);
//Convert int to NumericVector
NumericVector ID_vec(1);
ID_vec[0] = static_cast<double>(ID);
//Finding "ID_vec" matching value in "name1_list" vector
IntegerVector ID_pos = match(ID_vec,name1_list);
//Remove row from "data_df" with "ID" in column "name1"
data_df = subset(data_df, -ID_pos,R_MissingArg);
//Extract column "name1" from DataFrame "data_df", after removing "ID"
name1_list = as<NumericVector>(data_df["name1"]);
//Extract column "name1" from DataFrame "DF2"
Rcpp::NumericVector ID2_list = as<NumericVector>(DF2["name1"]);
//Finding "name1_list" matching value in "ID2_list" vector
IntegerVector ID2_pos = match(name1_list,ID2_list);
//Remove rows from "DF2" with "ID2_pos" in column "name1"
Rcpp::DataFrame tmpDF = subset(DF2, ID2_pos,R_MissingArg);
//Merge "data_df" and "DF2" by column "name" "ID2_pos" in column "name1"
const DataFrame& resDF = mergeDFs(Named("x")=data_df,Named("y")=DF2,Named("by")="name1");
//Add additional columns to the "resDF" dataframe
resDF["term1"] = abs(as<NumericVector>(resDF["factor1"]) - as<NumericVector>(resDF["factor2"]));
resDF["term2"] = Rcpp::pow((1 - as<NumericVector>(resDF["term1"])),TimeVal);
//Add values to row "i" and column "term_tot" of the dataframe "DF1"
Rcpp::NumericVector TermTot_Vector = as<NumericVector>(DF1["term_tot"]);
TermTot_Vector[i] = sum(as<NumericVector>(resDF["term2"]));
DF1["term_tot"] = TermTot_Vector;
};
return(DF1);
};
')
As an example to what ID_vector
, DF1
, DF2
and data_df
correspond to, consider the following:
ID_vector = c(1,3,5,9,13,14,22,39)
DF2 = data.frame(name1 = c(1,3,5,9,13,14,22,39), factor2 = rnorm(8,0,2))
DF1 = data.frame(name1 = c(1,3,5,9,13,14,22,39), term_tot = rep(NA,8))
data_df = data.frame(nameA = rep(3,8),name1 = c(1,3,5,9,13,14,22,39), factor1 = rnorm(8,0,1))
Note that I did not provide the path_data argument for reproducibility, since it woudl require the long list of files over which the for-loop goes. However, the structure of the data within the files is given by the data_df
dataframe. There, I would be mostly interested in knowing wether I am reading the file in the more efficient way.