我想以精确的方式生成加权随机数。我可以用一个例子来解释:我的输入数组是[1,2,3],它们的权重再次是[1,2,3]。在那种情况下,我希望看到1次1次,2次2次,3次3次。比如3 - > 2 - > 3 - > 1 - > 3 - > 2 ...
我使用rand()实现随机数生成,以获得[0,sum_of_weights]之间的范围。对于上面的示例,sum_of_weights = 1 + 2 + 3 = 6。我在互联网上搜索现有的解决方案,但结果不是我想要的。有时我在序列中得到2次以上且没有1次。它仍然加权但不完全给出我等待的次数。
我不确定下面的代码有什么问题。我应该做错事还是我尝试完全不同?谢谢你的回答。
int random_t (int items[], int items_weight[], int number_of_items)
{
double random_weight;
double sum_of_weight = 0;
int i;
/* Calculate the sum of weights */
for (i = 0; i < number_of_items; i++) {
sum_of_weight += items_weight[i];
}
/* Choose a random number in the range [0,1) */
srand(time(NULL));
double g = rand() / ( (double) RAND_MAX + 1.0 );
random_weight = g * sum_of_weight;
/* Find a random number wrt its weight */
int temp_total = 0;
for (i = 0; i < number_of_items; i++)
{
temp_total += items_weight[i];
if (random_weight < temp_total)
{
return items[i];
}
}
return -1; /* Oops, we could not find a random number */
}
我也尝试了不同的东西(代码如下)。它适用于我的情况,但整数溢出和广泛使用静态变量使它成为问题。
如果在给出NULL之前输入输入数组并继续使用它。有点类似于strtok()用法。
int random_w(int *arr, int weights[], int size)
{
int selected, i;
int totalWeight;
double ratio;
static long int total;
static long int *eachTotal = NULL;
static int *local_arr = NULL;
static double *weight = NULL;
if (arr != NULL)
{
free(eachTotal);
free(weight);
eachTotal = (long int*) calloc(size, sizeof(long));
weight = (double*) calloc(size, sizeof(double));
total = 0;
totalWeight = 0;
local_arr = arr;
for (i = 0; i < size; i++)
{
totalWeight += weights[i];
}
for (i = 0; i < size; i++)
{
weight[i] = (double)weights[i] / totalWeight;
}
srand(time(NULL));
}
while (1)
{
selected = rand() % size;
ratio = (double)(eachTotal[selected])/(double)(total+1);
if (ratio < weight[selected])
{
total++;
eachTotal[selected]++;
return local_arr[selected];
}
}
}
答案 0 :(得分:4)
这是你想要的吗?
# Weights: one 1, two 2s, three 3s
>>> import random
>>> vals = [1] * 1 + [2] * 2 + [3] * 3
>>> random.shuffle(vals)
>>> vals
[2, 3, 1, 2, 3, 3]
编辑:哎呀,出于某种原因,我的思想用Python替换了C标签。无论如何,我认为你想要的不是“加权”随机数发生器,而是一种洗牌。 This应该有所帮助。
答案 1 :(得分:1)
如果您说您没有“准确”获得每个加权值的预期值,那么您说的是多少次?如果您只进行了六次任何随机过程,我不希望您能够明确地说出任何有效的信息。您的代码可能正常工作。尝试运行它一百万次,然后检查结果。或者你可能真的想要Nathon所说的,一个预先加权的值列表,然后你可以随机地随机播放并且仍然具有你正在寻找的确切权重。
答案 2 :(得分:1)
您可以从multinomial distribution进行抽样。随机样本(或“桶中的球”)的范围为{1, 2, 3}
,观察每个样本的概率(“权重”)分别为{1/6, 2/6, 3/6}
。
出于演示目的,Perl脚本可以为您提供具有以下概率的标记球的观察列表:
#!/usr/bin/perl
use strict;
use warnings;
use Math::Random qw(random_multinomial);
use Data::Dumper;
my $events = 10;
my @probabilities = qw(0.167 0.333 0.5);
my @observations = random_multinomial($events, @probabilities);
print Dumper \@observations;
对于10个事件,单个试验将返回如下内容:
$VAR1 = 1;
$VAR2 = 2;
$VAR3 = 7;
这意味着您(在此单次试用中)有一个1
标记的事件,两个2
标记的事件和七个3
标记的事件。
如果您重复试用,则可能会对1
,2
和3
标记的事件进行不同的分发。
您可以轻松地将此列表构建到等效的{1, 2, 2, 3, 3, 3, 3, 3, 3, 3}
列表中。
随机随机播放第二个列表,以获得加权的观察到的随机数列表。
答案 3 :(得分:0)
如果你想让样本频率完全确定,我想 要走的路是生成一个具有适当出现次数的数组 对于每个值,然后进行随机shuffle(保留频率) 并将混洗数组的连续元素作为随机序列。
答案 4 :(得分:0)
所以按照你的例子:
然后生成1到10之间的随机数并返回映射的元素。 然后使用boost的uniform_int分布来获取一个数字然后映射。
这是生成数字的示例;然后,您需要映射结果:
#include <iostream>
#include <boost/random.hpp>
#include <time.h>
using namespace std;
using namespace boost;
int main ( ) {
uniform_int<> distribution(0, 10) ;
mt19937 engine;
engine.seed(time(NULL));
variate_generator<mt19937, uniform_int<> > myrandom (engine, distribution);
cout << myrandom() << endl;
}