给定迭代器获取N个样本

时间:2013-05-15 07:57:33

标签: algorithm sampling

给定的是数据点上的迭代器it,我们拥有的数据点数n,以及我们想要用来进行一些计算的最大样本数(maxSamples

想象一个函数calculateStatistics(Iterator it, int n, int maxSamples)。此函数应使用迭代器检索数据并对检索到的数据元素执行一些(重)计算。

  • if n <= maxSamples我们当然会使用从iterator获取的每个元素
  • 如果n > maxSamples,我们必须选择要查看的内容以及要跳过的内容

我花了很多时间在这上面。问题当然是如何选择何时跳过元素以及何时保留它。到目前为止我的方法:

  • 我不想从迭代器中获取第一个maxSamples,因为值可能不是均匀分布的。
  • 另一个想法是使用随机数生成器,让我在maxSamples0之间创建n(不同的)随机数,并将这些元素放在这些位置。但是,例如, n = 101maxSamples = 100在列表中找到一个新的不同号码变得越来越困难,只是在随机数生成中耗费了大量时间
  • 我的最后一个想法是反过来:生成n - maxSamples随机数并排除这些位置元素的数据元素。但这似乎也不是一个很好的解决方案。

你对这个问题有个好主意吗?是否有可能的标准已知算法?

4 个答案:

答案 0 :(得分:1)

为了提供一些答案,收集给定集合大小的一组随机数的好方法&gt;需要的元素如下。 (在C ++中是伪代码)。

编辑:你可能需要迭代并首先创建“someElements”向量。如果你的元素很大,它们可以成为这些元素的“指针”以节省空间。

vector randomCollectionFromVector(someElements, numElementsToGrab) {
    while(numElementsToGrab--) {
         randPosition = rand() % someElements.size();
         resultVector.push(someElements.get(randPosition))
         someElements.remove(randPosition);
    }
    return resultVector;
}

如果您不关心更改元素向量,也可以从someElements中删除随机元素,如您所述。该算法看起来非常相似,并且再次,这在概念上是相同的想法,您只需通过引用传递someElements并操纵它。

值得注意的是,伪随机分布的质量,随机分布的随机分布,随着您使用的分布大小的增加而增长。因此,如果您根据哪种方法选择使用哪种方法导致使用更多随机数,您可能会获得更好的结果。示例:如果您有100个值,并且需要99,那么您应该选择99个值,因为这将导致您使用99个伪随机数,而不仅仅是1.相反,如果您有1000个值,并且需要99,那么您应该可能更喜欢删除901值的版本,因为您使用了psuedo随机分布中的更多数字。如果你想要的是一个可靠的随机分布,这是一个非常简单的优化,这将大大提高你看到的“假随机性”的质量。或者,如果绩效比分配更重要,那么您可以采取替代方案,甚至只是抓住前99个方法。

答案 1 :(得分:1)

interval = n/(n-maxSamples) //an euclidian division of course
offset = random(0..(n-1)) //a random number between 0 and n-1
totalSkip = 0
indexSample = 0;
FOR it IN samples DO
    indexSample++ // goes from 1 to n
    IF totalSkip < (n-maxSamples) AND indexSample+offset % interval == 0 THEN
        //do nothing with this sample
        totalSkip++
    ELSE
        //work with this sample
    ENDIF
ENDFOR
ASSERT(totalSkip == n-maxSamples) //to be sure

interval表示要跳过的两个样本之间的距离。 offset不是强制性的,但它允许具有非常小的多样性。

答案 2 :(得分:1)

根据讨论,并更好地了解您的问题,我建议如下。您可以利用素数属性,我认为这将为您提供一个非常好的解决方案,它似乎会抓取伪随机数。它在以下代码中说明。

#include <iostream>
using namespace std;


int main() {
    const int SOME_LARGE_PRIME = 577;  //This prime should be larger than the size of your data set.  
    const int NUM_ELEMENTS = 100;
    int lastValue = 0;
    for(int i = 0; i < NUM_ELEMENTS; i++) {
        lastValue += SOME_LARGE_PRIME;
        cout << lastValue % NUM_ELEMENTS << endl;
    }
}

使用此处提供的逻辑,您可以创建一个包含从1到“NUM_ELEMENTS”的所有值的表格。由于素数的属性,在您完全旋转回数据集的大小之前,您不会得到任何重复项。如果你接下来的第一个“NUM_SAMPLES”,并对它们进行排序,你可以迭代你的数据结构,并获取数字的伪随机分布(不是很好的随机,但比预定的间隔更随机),没有额外的空间,只有一次通过您的数据。更好的是,您可以通过每次抓取一个随机素数来更改分布的布局,同样必须大于您的数据集,或者以下示例中断。

PRIME = 3,数据集大小= 99.无效。

当然,最终这与预先确定的间隔非常相似,但它会通过简单地抓取每个“size / num_samples”元素来插入一个你无法获得的随机性。

答案 3 :(得分:0)

这称为水库采样