R ++中C ++的std :: discrete_distribution与sample()的行为

时间:2018-05-02 20:34:58

标签: c++ random statistics std distribution

我想从一组频率中绘制一个数字,直到所有值都为零。通过绘制剩余数字的频率正在减少。在R中有一个“简单”的函数样本为我做。在C ++中,我找到了std :: discrete_distribution,但没有关于它的详细信息

  1. 我无法找到R和/或std :: discrete_distribution算法的明确描述来比较功能。行为是否相同?我可以用这个C ++ STDL解决我的任务吗?
  2. 当我编写其他PRNG的非STDL时 - 需要它们的功能,以便它们可以与std :: discrete_distribution一起使用--cppreference和其他站点/论坛对此非常沉默
  3. 在我的代码中的第二个位置我需要一个类似的行为(每次绘制的固定频率)我发现没有明确的额外调用或参数来分离两个功能。我是否需要使用降低的参数创建新实例?!这显然是我无法相信的事情......
  4. 实际上我将频率(由std :: vector保持)求和,直到随机数小于或等于。这是:

    • 时间/资源无效
    • 我不确定这是否在统计上允许

    我希望能在你的帮助下找到更好的解决方案。

    感谢您的时间,支持和答案:)

1 个答案:

答案 0 :(得分:0)

C ++ 17为我们提供了std::sample函数:

#include <iostream>
#include <random>
#include <string>
#include <iterator>
#include <algorithm>

int main()
{
    std::string in = "abcdefgh";
    std::string out;

    std::sample(in.begin(), in.end(), 
                std::back_inserter(out),
                5,
                std::mt19937{std::random_device{}()} //(*)
                );

    std::cout << "five random letters out of " << in << " : " << out << '\n';
}

如果你没有C ++ 17,那么提案A sample Proposal, v4包含一个示例实现(使用uniform_int_distribution):

// the primary function, which calls the detailed functions depending on types of iterators in the used containers.
template< class PopIter, class SampleIter, class Size, class URNG >
SampleIter sample( PopIter first, PopIter last, SampleIter out, Size n, URNG&& g )
{
    using pop_t  = typename std::iterator_traits< PopIter >::iterator_category;
    using samp_t = typename std::iterator_traits< SampleIter >::iterator_category;
    return __sample( first, last, pop_t{}, out, samp_t{}, n, forward< URNG >( g ) );
}

template< class PopIter, class SampleIter, class Size, class URNG >
SampleIter __sample( PopIter first,
                     PopIter last,
                     std::input_iterator_tag,
                     SampleIter out,
                     std::random_access_iterator_tag,
                     Size   n,
                     URNG&& g )
{
    using dist_t  = std::uniform_int_distribution< Size >;
    using param_t = typename dist_t::param_type;
    dist_t d{};
    Size   sample_sz{0};
    while ( first != last && sample_sz != n )
        out[ sample_sz++ ] = *first++;
    for ( Size pop_sz{sample_sz}; first != last; ++first, ++pop_sz )
    {
        param_t const p{0, pop_sz};
        Size const    k{d( g, p )};
        if ( k < n )
            out[ k ] = *first;
    }
    return out + sample_sz;
}

template< class PopIter, class SampleIter, class Size, class URNG >
SampleIter __sample( PopIter first,
                     PopIter last,
                     std::forward_iterator_tag,
                     SampleIter out,
                     std::output_iterator_tag,
                     Size   n,
                     URNG&& g )
{
    using dist_t  = std::uniform_int_distribution< Size >;
    using param_t = typename dist_t::param_type;
    dist_t d{};
    Size   unsampled_sz = std::distance( first, last );
    for ( n = min( n, unsampled_sz ); n != 0; ++first )
    {
        param_t const p{0, --unsampled_sz};
        if ( d( g, p ) < n )
        {
            *out++ = *first;
            --n;
        }
    }
    return out;
}