随机抽样c ++的最佳方法

时间:2014-09-16 08:26:57

标签: c++ visual-c++ vector

我有一个长度为1百万(0到1百万)的数据向量A.从A开始,我想创建包含A的索引的向量B(其长度仅为A的10%)。这些索引是从A中随机抽取的样本索引。我尝试使用srand()和random_shuffle,这是一个很好的为非常大的向量提取样本的方法?任何人都可以建议我。

  std::vector <int> samplingIndex;

   for (int i = 0; i < 1000000; ++i) { samplingIndex.push_back(i); } 
   std::srand(50); 
   std::random_shuffle(samplingIndex.begin(), samplingIndex.end());

在此之后,我从samplingIndex中取出前10%的索引来制作B。

4 个答案:

答案 0 :(得分:1)

您可以使用Fisher–Yates shuffle,然后避免构建庞大的数组a

类似的东西:

// Fisher–Yates_shuffle
std::vector<int> FisherYatesShuffle(std::size_t size, std::size_t max_size, std::mt19937& gen)
{
    assert(size < max_size);
    std::vector<int> b(size);

    for(std::size_t i = 0; i != max_size; ++i) {
        std::uniform_int_distribution<> dis(0, i);
        std::size_t j = dis(gen);
        if(j < b.size()) {
            if(i < j) {
                b[i] = b[j];
            }
            b[j] = i;
        }
    }
    return b;
}

Live example

答案 1 :(得分:0)

似乎合理。一个调整是你可以用这个替换你的for循环,以避免重复重新分配向量:

std::vector <int> samplingIndex(1000000);
std::iota(samplingIndex.begin(), samplingIndex.end(), 0);

如果您的收益百分比远小于10%,那么在[0,len(A))中生成随机数是值得的,直到您得到len(B)不同的值。

答案 2 :(得分:0)

您的代码是使用旧的C ++编写的。我认为你应该仔细研究新的C ++ 11/14中的随机性。

http://en.cppreference.com/w/cpp/algorithm/random_shuffle

答案 3 :(得分:0)

如果您的输入来自AWGN源(或接近它),您可以每10个样本选择1个样本并在O(N)时间内完成工作(您希望10%的随机样本正确吗?)

否则,从巨大的矢量中提取10%的随机样本的一种非常有效的方法是每次选择的索引随机存储样本。继续挑选随机项目,如果已​​经采用了索引则重复。是的,是一种概率方法,但您在最佳和平均情况下实现了O(N)复杂性。最糟糕的情况是你一次又一次地选择相同的索引,但这意味着一个非常糟糕的PRNG实现:你可以假设最坏的情况是一个非常不可能的情况(只是保持在哈希函数中的几率足够低)

您还可以使用链接列表和&#34;短路&#34;选定的样本(将PRNG输出空间减少到N-1)但这需要额外的内存来存储链表。