簡體   English   中英

隨機抽樣c ++的最佳方法

[英]best way of random sampling c++

我有一個長度為 100 萬(0 到 100 萬)的數據向量 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。

您可以使用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> res(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 < res.size()) {
            if (i < res.size()) {
                res[i] = res[j];
            }
            res[j] = i;
        }
    }
    return res;
}

活生生的例子

似乎有道理。 一個調整是你可以用這個替換你的 for 循環以避免重復重新分配向量:

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

如果您的占比遠小於 10%,則值得只在 [0, len(A)) 中生成隨機數,直到獲得 len(B) 不同的值。

您的代碼是使用舊 C++ 編寫的。 我認為您應該仔細研究新 C++11/14 中的隨機性。

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

如果您的輸入來自 AWGN 源(或接近它),您可以每 10 個樣本選擇 1 個樣本並在 O(N) 時間內完成工作(您想要 10% 的隨機樣本對嗎?)

否則,從一個巨大的向量中提取 10% 的隨機樣本的一種非常有效的方法是在每次選擇索引時隨機存儲樣本。 繼續選擇隨機項目,如果索引已被采用,則重復。 是的,是一種概率方法,但您在最佳和平均情況下實現了 O(N) 復雜度。 最壞的情況是您一次又一次地選擇相同的索引,但這意味着 PRNG 實現非常非常糟糕:您可以假設最壞的情況是非常不可能的情況(只需保持足夠低的幾率,就像在散列函數中一樣)

您還可以使用鏈表並“短路”選定的樣本(將 PRNG 輸出空間減少到 N-1),但這需要額外的內存來存儲鏈表。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM