2016-12-08 2 views
1

Я хочу создать случайный вектор из 5 целых чисел из диапазона, например: 1:10. Я могу использовать ТОЛЬКО базовый Rcpp. (Без библиотек C)Создание образца целых чисел в Rcpp

В настоящее время у меня есть:

#include <Rcpp.h> 
using namespace Rcpp; 
// [[Rcpp::export]] 
NumericVector test(){ 
NumericVector z(5); 
for (int i=0; i<5 ++i) 
z[i] = R::runif(1,10); 
return z; 
} 
/***R 
test() 
*/ 

Но:

  • это не целое

  • он не является уникальным.

+0

Конечно, моя ошибка. Готово. – AgnieszkaTomczyk

+1

Можете ли вы подробнее остановиться на этом: * «Я могу использовать ТОЛЬКО базовый Rcpp (без библиотек C)» *? Стандартные библиотеки C и C++ доступны при каждой установке Rcpp, так что в чем проблема? – nrussell

+0

Я имею в виду дополнительные математические библиотеки, например, Armadillo – AgnieszkaTomczyk

ответ

5

Это может быть сделано сжато с std::random_shuffle: выход

#include <Rcpp.h> 

// [[Rcpp::export]] 
Rcpp::IntegerVector sample_int() { 
    Rcpp::IntegerVector pool = Rcpp::seq(1, 10); 
    std::random_shuffle(pool.begin(), pool.end()); 
    return pool[Rcpp::Range(0, 4)]; 
} 

Пример:

sample_int() 
# [1] 9 2 5 1 7 

sample_int() 
# [1] 1 10 5 3 8 

sample_int() 
# [1] 5 9 3 2 8 

И для записи, вы код не возвращался, потому что целые

  • ::runifdouble значения; и
  • вашей функции в возвращаемый тип был NumericVector, а не IntegerVector

Хотя это является несущественным при работе с малыми диапазонами, таких как той, которая используется в вашем примере (1, ..., 10), это подход не очень эффективен (особенно когда количество отбираемых элементов намного меньше, чем пул рисования), так как std::random_shuffle перетасовывает весь диапазон. С парой вспомогательных функций, мы можем сделать лучше (при условии, std::rand «достаточно» случайная для ваших целей):

#include <Rcpp.h> 

// C++ 98 
template <typename Iter, typename T> 
inline void iota(Iter first, Iter last, T value) { 
    while (first != last) { 
     *first++ = value++; 
    } 
} 

template <typename T> 
inline T pop_random(std::vector<T>& v) { 
    typename std::vector<T>::size_type pos = std::rand() % v.size(); 
    T res = v[pos]; 

    std::swap(v[pos], v.back()); 
    v.pop_back(); 

    return res; 
} 

// [[Rcpp::export]] 
Rcpp::IntegerVector sample_int2(int n, int min, int max) { 
    Rcpp::IntegerVector res(n); 
    std::vector<int> pool(max + 1 - min); 
    iota(pool.begin(), pool.end(), min); 

    for (R_xlen_t i = 0; i < n; i++) { 
     res[i] = pop_random(pool); 
    } 

    return res; 
} 

И обобщая оригинальное решение для сравнения:

// [[Rcpp::export]] 
Rcpp::IntegerVector sample_int(int n, int min, int max) { 
    Rcpp::IntegerVector pool = Rcpp::seq(min, max); 
    std::random_shuffle(pool.begin(), pool.end()); 
    return pool[Rcpp::Range(0, n - 1)]; 
} 

microbenchmark::microbenchmark(
    "sample_int" = sample_int(100, 1, 1e6), 
    "sample_int2" = sample_int2(100, 1, 1e6), 
    times = 300L 
) 
# Unit: milliseconds 
#   expr  min  lq  mean median  uq  max neval 
# sample_int 20.639801 22.417594 23.603727 22.922765 23.735258 35.531140 300 
# sample_int2 1.504872 1.689987 1.789866 1.755937 1.830249 2.863399 300 

microbenchmark::microbenchmark(
    "sample_int" = sample_int(1e5, 1, 1e6), 
    "sample_int2" = sample_int2(1e5, 1, 1e6), 
    times = 300L 
) 
# Unit: milliseconds 
#   expr  min  lq  mean median  uq  max neval 
# sample_int 21.08035 22.384714 23.295403 22.811011 23.282353 34.068462 300 
# sample_int2 3.37047 3.761608 3.992875 3.945773 4.086605 9.134516 300 
+3

Нарушает собственное требование OP «нет библиотек» и получает через OP через минуту. Рассказывает вам что-то, не уверен, что я хочу знать, что ;-) –

Смежные вопросы