生成随机轮询号码

问题描述 投票:2回答:6

我为这个简单的问题苦苦挣扎:我想创建一些随机的民意调查数字。我有4个变量需要填充数据(实际上是一个整数数组)。这些数字应代表随机百分比。所有百分比均为100%。听起来很简单。

但我认为这并不容易。我的第一次尝试是生成一个介于10和base(base = 100)之间的随机数,并减去基数中的数字。这样做了3次,最后一个值被分配了基数。有更优雅的方式吗?

我的问题用几句话说:

如何用随机值填充此数组,这些值在加在一起时将为100?

int values[4];

c random
6个回答
5
投票

您需要编写代码来模拟您正在模拟的内容。

因此,如果您有四个选择,则生成随机数的样本大小(0..1 * 4),然后将所有0,1,2和3加起来(记住4不会被选中)。然后将计数除以样本大小。

for (each sample) {
   poll = random(choices);
   survey[poll] += 1;
}

使用计算机模拟事物很容易,简单的模拟速度非常快。

请记住,您正在使用整数,并且整数不会很好地划分而不将它们转换为浮点数或双精度数。如果你错过了几个百分点,则可能与整数除以余数有关。


2
投票

你在这里有一个问题是将数字100分成4个随机整数。这叫做partitioning in number theory。 这个问题已经解决了here。在那里提出的解决方案主要有以下几点: 如果计算,在n时间有一个整数O(n^2)的分区数。这产生了一个大小为O(n^2)的表,然后可以用它来生成knth分区,对于任何整数k,在O(n)时间。 在你的情况下,n = 100k = 4


1
投票

在范围<0..1>中生成x1,从1减去它,然后在范围<0..1-x1>中生成x2,依此类推。最后一个值不应该是randomed,但在你的情况下等于1-x1-x2-x3。


1
投票

我不认为这比你已经完成的听起来更漂亮,但确实有效。 (唯一的优点是,如果你想要超过4个元素,它是可扩展的)。

确保你#include <stdlib.h>

int prev_sum = 0, j = 0;
for(j = 0; j < 3; ++j)
{
    values[j] = rand() % (100-prev_sum);
    prev_sum += values[j];
}
values[3] = 100 - prev_sum;

1
投票

为“随机分区”问题提供真正无偏见的解决方案需要一些工作。但首先必须了解“无偏见”在这种背景下意味着什么。

一条推理是基于随机抛硬币的直觉。一个没有偏见的硬币会像尾巴一样经常出现,因此我们可能会认为通过将无偏硬币投掷100次并计数,我们可以将100个投掷的无偏分区分为两个部分(头数和尾数)。 。这是Edwin Buck's proposal的本质,修改为生成四分区而不是两分区。

但是,我们会发现许多分区永远不会出现。有101个两个分区100 - {0, 100}, {1, 99} … {100, 0}但硬币采样解决方案在10,000次尝试中发现不到一半。正如可以预料的那样,分区{50, 50}是最常见的(7.8%),而从{0, 100}{39, 61}的所有分区总共达到不到1.7%(并且在我做的试验中,从{0, 100}{31, 69}的分区没有' t出现了。)[注1]

因此,这似乎不是可能分区的无偏见样本。无偏见的分区样本将以相同的概率返回每个分区。

因此,另一个诱惑是从所有可能的大小中选择分区的第一部分的大小,然后从剩下的任何大小中选择第二部分的大小,依此类推,直到我们达到小于大小的一个。分区,此时剩下的东西都在最后一部分。然而,这也会产生偏差,因为第一部分比任何其他部分都要大得多。

最后,我们可以枚举所有可能的分区,然后随机选择其中一个。这显然是公正的,但不幸的是,有很多可能的分区。例如,对于4分区为100的情况,有176,581种可能性。也许在这种情况下这是可行的,但似乎不会导致一般解决方案。

为了更好的算法,我们可以从观察分区开始

{p1, p2, p3, p4}

可以在没有偏见的情况下重写为累积分布函数(CDF):

{p1, p1+p2, p1+p2+p3, p1+p2+p3+p4}

最后一项只是所需的总和,在这种情况下为100。

那仍然是[0,100]范围内的四个整数的集合;但是,它保证按顺序递增。

生成以100结尾的四个数字的随机排序序列并不容易,但生成三个不大于100的随机整数,排序它们然后找到相邻差异是微不足道的。这导致了一个几乎无偏见的解决方案,这对于大多数实际目的而言可能足够接近,特别是因为实现几乎是微不足道的:

(蟒蛇)

def random_partition(n, k):
  d = sorted(randrange(n+1) for i in range(k-1))
  return [b - a for a, b in zip([0] + d, d + [n])]

不幸的是,由于sort,这仍然有偏见。选择未排序列表时没有偏离可能列表的范围,但排序步骤不是简单的一对一匹配:具有重复元素的列表比没有重复元素的列表具有更少的排列,因此特定排序列表的概率没有重复比具有重复的排序列表的概率高得多。

随着n相对于k变大,具有重复的列表的数量迅速下降。 (这些对应于其中一个或多个部分为0的最终分区。)在渐近线中,我们从连续体中选择并且碰撞具有概率0,该算法是无偏的。即使在n = 100,k = 4的情况下,对于许多实际应用,偏差也可能是可忽略的。将n增加到1000或10000(然后缩放得到的随机分区)将减少偏差。

有快速算法可以产生无偏的整数分区,但它们通常难以理解或缓慢。需要时间(n)的慢速类似于reservoir sampling;要获得更快的算法,请参阅Jeffrey Vitter.的工作


Notes

  1. 这是快速而肮脏的Python + shell测试: $ python -c ' from random import randrange n = 2 for i in range(10000): d = n * [0] for j in range(100): d[randrange(n)] += 1 print(' '.join(str(f) for f in d)) ' | sort -n | uniq -c 1 32 68 2 34 66 5 35 65 15 36 64 45 37 63 40 38 62 66 39 61 110 40 60 154 41 59 219 42 58 309 43 57 385 44 56 462 45 55 610 46 54 648 47 53 717 48 52 749 49 51 779 50 50 788 51 49 723 52 48 695 53 47 591 54 46 498 55 45 366 56 44 318 57 43 234 58 42 174 59 41 118 60 40 66 61 39 45 62 38 22 63 37 21 64 36 15 65 35 2 66 34 4 67 33 2 68 32 1 70 30 1 71 29

-2
投票

你可以强制它,创建一个计算函数,将数字中的数字相加。如果它们不等于100,则重新生成数组中的随机值,再次进行计算。

© www.soinside.com 2019 - 2024. All rights reserved.