给定的是数据点上的迭代器it
,我们拥有的数据点数n
,以及我们想要用来进行一些计算的最大样本数(maxSamples
)
想象一个函数calculateStatistics(Iterator it, int n, int maxSamples)
。此函数应使用迭代器检索数据并对检索到的数据元素执行一些(重)计算。
n <= maxSamples
我们当然会使用从iterator获取的每个元素n > maxSamples
,我们必须选择要查看的内容以及要跳过的内容我花了很多时间在这上面。问题当然是如何选择何时跳过元素以及何时保留它。到目前为止我的方法:
maxSamples
,因为值可能不是均匀分布的。 maxSamples
和0
之间创建n
(不同的)随机数,并将这些元素放在这些位置。但是,例如, n = 101
和maxSamples = 100
在列表中找到一个新的不同号码变得越来越困难,只是在随机数生成中耗费了大量时间n - maxSamples
随机数并排除这些位置元素的数据元素。但这似乎也不是一个很好的解决方案。你对这个问题有个好主意吗?是否有可能的标准已知算法?
答案 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)
这称为水库采样