【问题标题】:Filling a new vector by sampling without replacement from an old one通过采样而不替换旧向量来填充新向量
【发布时间】:2016-04-26 16:12:07
【问题描述】:

在 C++ 中是否有一种无需替换的良好且高效的采样算法,可以轻松应用于以下函数?

它需要两个向量,newold,并通过从前者重复采样将后者填充到一个循环中(rng.i0 是一个随机数生成器函数,我使用它返回一个介于 0 和给定值)。

void diluationexpansionstep(std::vector<long> &oldpopulation,
                            std::vector<long> &newpopulation,
                            long newpopsize)
{
    for (int i = 1; i <= newpopsize;i++) {
        int index_a = rng.i0(oldpopulation.size());
        newpopulation.push_back(oldpopulation[index_a]);
    }
}

更新::

感谢您提供有用的回复。因为我想使用我自己的 RNG 而不是 C++ 中的内置 RNG,所以我最终构建了以下基于 Fisher Yates 的函数,其中 rng.i0 是一个返回 0 和整数参数之间的随机整数的函数。

void FisherYatesShuffle(vector<long> &indices){
    for (int k = 0; k < indices.size(); k++) {
        int r = k + rng.i0(indices.size()-k);
        swap(indices[k], indices[r]);
        }
    }

void diluationexpansionstep(std::vector<long> &oldpopulation,
                            std::vector<long> &newpopulation,
                            long newpopsize){
    vector<long> indices(oldpopulation.size());
    std::iota(std::begin(indices),std::end(indices),0);
    FisherYatesShuffle(indices);
    for (int i = 0; i <= newpopsize-1;i++){
        newpopulation.push_back(oldpopulation[indices[i]]);
        }
    }

据我所知,这项工作可以准确而合理地快速完成。

【问题讨论】:

  • 不是您的示例采样 with 替换,因为您没有从 oldpopulation 中删除任何内容,并且您没有确保您选择的索引不是t dups(除非那是 rng.i0 在做什么,我不认识)?
  • 我不确定你想在这里问什么。您能否澄清“无需替换”,您能否提供 rng.i0(...) 因为您要求“可以轻松应用于以下功能”。你的问题到底是什么?
  • @Elyasin - 我假设“没有替换”意味着从源中选择一个随机元素,然后从减少的源中选择一个后续元素(删除第一个元素),等等。换句话说,选择“无替换”与选择“有替换”的标准定义。
  • 用“不重复”来形容不是更准确吗?

标签: c++ c++11 vector shuffle


【解决方案1】:

使用来自&lt;algorithm&gt;std::random_shuffle 来最小化开发人员时间和最大化正确性的“良好且高效”的算法:

#include <algorithm>
#include <cassert>
#include <iostream>
#include <vector>

using namespace std;

vector<long> random_sample_without_replacement(const vector<long>& source, int newpopsize)
{
    assert(newpopsize >= 0 && newpopsize <= source.size());
    auto result { source };
    std::random_shuffle(result.begin(), result.end());
    result.resize(newpopsize);
    return result;
}

int main() {
    vector<long> test { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    auto result { random_sample_without_replacement(test, 5) };
    for (auto& e : result) cout << e << " ";
    cout << endl;
    return 0;
}

Working example here.

【讨论】:

  • 我不确定这是否是问题的答案。
  • @T.C.以“最大限度地减少开发人员时间和最大限度地提高正确性”来衡量的“良好和高效”的哪一部分在这里没有得到满足?
  • 从“使用已在 C++17 中删除的弃用函数”开始。
  • @T.C.天哪,我想我不知道。但由于这个问题的标签是 C++11,我不知道这很重要。我想当这很重要时,这个代码示例可以更改为std::shuffle。那么它会是“好的和有效的”吗?
  • 您引入了两个原始约束没有的约束 - newpopsize 不能为 0,并且 newpopsize 不能大于源。
猜你喜欢
  • 1970-01-01
  • 2016-12-25
  • 1970-01-01
  • 2020-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-07
相关资源
最近更新 更多