简体   繁体   中英

C++ Armadillo: Get the ranks of the elements in a vector

Suppose I have a vector, and I want to get the ranks of the elements if they were sorted.

So if I have the vector:

0.5
1.5
3.5
0.1

and I need returned the ranks of each element:

2
3
4
1

Is there a way to do this in Armadillo? This is different than the previous post since we are getting the ranks and not the indices before sorting.

Here, check this out:

#include<iostream>
#include<vector> // std:: vector
#include <algorithm> // std::sort
#include <map> // std::map

using namespace std;


int main() {
    vector<double> myVector = { 0.5, 1.5, 3.5, 0.1 };
    vector<double> Sorted = myVector;

    std::sort(Sorted.begin(), Sorted.end());

    map<double, int> myMap;

    for (int i = 0; i < Sorted.size() ; i++)
    {
        myMap.insert(make_pair(Sorted[i],i));
    }

    for (int i = 0; i < myVector.size() ; i++)
    {
        auto it = myMap.find(myVector[i]);
        cout << it->second + 1 << endl;
    }

    return 0;
};

Output:

在此处输入图片说明

Here is my codes using STL to get the rankings in a concise way

template <typename T>
vector<size_t> calRank(const vector<T> & var) {
    vector<size_t> result(var.size());
    //sorted index
    vector<size_t> indx(var.size());
    iota(indx.begin(),indx.end(),0);
    sort(indx.begin(),indx.end(),[&var](int i1, int i2){return var[i1]<var[i2];});
    //return ranking
    for(size_t iter=0;iter<var.size();++iter){
        //it may cause overflow for a really long vector, in practice it should be ok.
        result[indx[iter]]=iter+1;
    }
    return result;
}

Here is a solution in pure Armadillo code, using the function arma::sort_index() .

The function arma::sort_index() calculates the permutation index to sort a given vector into ascending order.

Applying the function arma::sort_index() twice: arma::sort_index(arma::sort_index())} , calculates the reverse permutation index to sort the vector from ascending order back into its original unsorted order. The ranks of the elements are equal to the reverse permutation index.

Below is Armadillo code wrapped in RcppArmadillo that defines the function calc_ranks() . The function calc_ranks() calculates the ranks of the elements of a vector, and it can be called from R .

#include <RcppArmadillo.h>
using namespace Rcpp;
using namespace arma;
// [[Rcpp::depends(RcppArmadillo)]]

// Define the function calc_ranks(), to calculate 
// the ranks of the elements of a vector.
//
// [[Rcpp::export]]
arma::uvec calc_ranks(const arma::vec& da_ta) {
  return (arma::sort_index(arma::sort_index(da_ta)) + 1);
}  // end calc_ranks

The above code can be saved to the file calc_ranks.cpp , so it can be compiled in R using the function Rcpp::sourceCpp() .

Below is R code to test the function calc_ranks() (after it's been compiled in R ):

# Compile Rcpp functions
Rcpp::sourceCpp(file="C:/Develop/R/Rcpp/calc_ranks.cpp")

# Create a vector of random data
da_ta <- runif(7)
# Calculate the ranks of the elements
calc_ranks(da_ta)

# Compare with the R function rank()
all.equal(rank(da_ta), drop(calc_ranks(da_ta)))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM