【问题标题】:randomly sample vector of tuples with weights in C++在 C++ 中随机采样具有权重的元组向量
【发布时间】:2017-10-26 14:08:37
【问题描述】:

我想知道是否有人可以提供帮助。

我正在寻找一种从具有权重的元组向量中进行采样的相当简单且理想的快速方法。

例如假设我有一个元组向量,每个元组都包含一个值和相应的权重/概率:

vector<tuple<int, double>> foo = { {1,0.04},{2,0.8},{ 3,0.01 },{ 4,0.03 },{ 
5,0.1 },{ 6,0.9 } };

我想通过 foo 并根据权重随机抽样,所以我最终会得到一个向量(一个新向量或替换 foo 中的元素),在这种情况下,问题主要是 2 和6.例如

 vector<tuple<int, double>> bar = { {2,0.8},{2,0.8},{ 6,0.9},{ 6,0.9 },{ 
6,0.9 },{ 6,0.9 } };

我确信使用 std::discrete_distribution 之类的方法非常简单,尽管我还没有弄清楚具体方法。

编辑: 感谢您到目前为止的帮助,我可能在“重新采样”时使用了一些糟糕的术语。

本质上,我想要的是采用上述元组“foo”的向量,并生成一个与 foo 大小相同的新向量“bar”,并由 foo 的元组组成,但元组是根据元组中的概率加权随机选择。 - 希望这是有道理的。

【问题讨论】:

  • re-sample 你在做什么?是什么让价值观发生了变化?
  • 你能详细说明你想要的输出是什么吗?我只是无法从你的问题中理解你在问什么(可能是因为我只是缺乏你的术语的领域知识)。
  • 我很困惑。分布有变化吗?为什么说“重新采样”而不是“采样”?如果 foo 提供了可用的选择和概率,那么实际结果是完全不同的(并且不包括任何概率,只是简单的整数,随机选择的)。

标签: c++ vector random tuples


【解决方案1】:

像这样的东西?

// Example program
#include <iostream>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::discrete_distribution<> d({0.04, 0.8, 0.01, 0.03, 0.1, 0.9});
    std::map<int, int> m;
    for(int n=0; n<100000; ++n) {
        ++m[d(gen)];
    }
    for(auto p : m) {
        std::cout << p.first+1 << " generated " << p.second << " times\n";
    } 
 }

1 generated 2089 times
2 generated 42472 times
3 generated 544 times
4 generated 1631 times
5 generated 5473 times
6 generated 47791 times

【讨论】:

    【解决方案2】:

    是的,std::discrete_distribution 可以。下面使用权重来置换对的向量。正如人们所期望的那样,它往往会收敛到 2 或 6。

    #include <random>
    #include <vector>
    #include <tuple>
    #include <iostream>
    
    std::ostream& operator<<(std::ostream& os,const std::vector<std::tuple<int, double>>& v)
    {
        for(auto&& i : v)
            std::cout << "{" << std::get<0>(i) << ", " << std::get<1>(i) << "}\t";
        return os;
    }
    
    auto permute(std::vector<std::tuple<int, double>>& foo)
    {
        std::vector<std::tuple<int, double>> temp;              // return value
        std::vector<double> v;                                  // weights
        for(auto&& i : foo)
            v.push_back(std::get<1>(i));                        // get weights
        std::discrete_distribution<int> dd{v.begin(), v.end()}; // create distribution
        static std::random_device rd;
        for(size_t i{}; i < foo.size(); ++i)
            temp.push_back(foo[dd(rd)]);                        // build return vector by selecting from foo according to weights
        return temp;
    }
    
    int main()
    {
        std::vector<std::tuple<int, double>> foo = {{1, 0.04}, {2, 0.8}, {3, 0.01}, {4, 0.03}, {5, 0.1}, {6, 0.9}};
        std::cout << foo << '\n';
        for(size_t i{}; i < 10; ++i) {
            foo = permute(foo);
            std::cout << foo << '\n';
        }
    }
    

    样本输出:

    {1, 0.04}       {2, 0.8}        {3, 0.01}       {4, 0.03}       {5, 0.1}        {6, 0.9}
    {2, 0.8}        {5, 0.1}        {6, 0.9}        {2, 0.8}        {6, 0.9}        {6, 0.9}
    {6, 0.9}        {2, 0.8}        {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}
    {6, 0.9}        {6, 0.9}        {6, 0.9}        {2, 0.8}        {6, 0.9}        {6, 0.9}
    {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}        {2, 0.8}
    {6, 0.9}        {6, 0.9}        {2, 0.8}        {6, 0.9}        {6, 0.9}        {6, 0.9}
    {6, 0.9}        {6, 0.9}        {2, 0.8}        {6, 0.9}        {2, 0.8}        {6, 0.9}
    {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}        {2, 0.8}
    {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}
    {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}
    {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}        {6, 0.9}
    

    【讨论】:

    • 使用std::random_device 作为分发生成器?我知道这在形式上是可以的,但这是个好主意吗?
    • 等等,我敢肯定这是个坏主意,因为无法保证 random_device 实际上是不确定的......
    • @MassimilianoJanes 我将随机设备设为静态。你是这个意思吗?
    • 解决了部分问题;使用非确定性源仍然可能存在性能/质量问题......这在标准中没有明确说明,但我读过的所有资源(包括 作者)仅使用 random_device 作为播种器;我会改用 default_random_engine
    • @MassimilianoJanes 解决您提到的所有问题是more involved,而不是简单地使用默认随机引擎。该标准指出,提供std::default_random_engine“以便为相对随意、不熟练和/或轻量级的使用提供至少可接受的引擎行为。”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-19
    • 1970-01-01
    • 2021-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多