Php 根据给定的一组数字和机会生成一个随机数
我有一个数字列表,比如Php 根据给定的一组数字和机会生成一个随机数,php,algorithm,random,probability,Php,Algorithm,Random,Probability,我有一个数字列表,比如 $list = array(1,5,19,23,59,51,24) 在实际代码中,这是从数据库生成的,所以这个数组最多可以容纳500个彼此不同的数字 数据库中的每个数字都有发生的概率。所以我有一个以前执行的数据来生成从1到500的随机数,并记录了每个数字生成1000次的概率 现在有了数字的列表和每个数字的概率,我想写一个函数,根据它们的概率从这500个数字中生成一个随机数 例如: number 1 has a chance of: 0.00123 //0.1
$list = array(1,5,19,23,59,51,24)
在实际代码中,这是从数据库生成的,所以这个数组最多可以容纳500个彼此不同的数字
数据库中的每个数字都有发生的概率。所以我有一个以前执行的数据来生成从1到500的随机数,并记录了每个数字生成1000次的概率
现在有了数字的列表和每个数字的概率,我想写一个函数,根据它们的概率从这500个数字中生成一个随机数
例如:
number 1 has a chance of: 0.00123 //0.123%
number 6 has a chance of: 0.0421 //4.21%
number 11 has a chance of: 0.0133 //1.33%
所以变量$finallist将如下所示:
$finallist[1] = 0.00123;
$finallist[6] = 0.0421;
$finallist[11] = 0.0133;
现在,如果我运行我的函数并传入$finallist作为一个参数,我想检索一个介于1和6之间的随机数,但是数字6出现的可能性大于1,11出现的可能性大于1 我编写了一些函数,处理根据随机数的概率返回随机数,但它只接受1个值作为参数
private function randomWithProbability($chance, $num, $range = false)
{
/* first generate a number 0 and 1 and see if that number is in the range of chance */
$rand = $this->getRandomFloatValue(0, 1);
if ($rand <= $chance)
{
/* the number should be returned */
return $num;
}
else
{
/* otherwise return a random number */
if ($range !== false)
{
/* make sure that this number is not same as the number for which we specified the chance */
$rand = mt_rand(1, $range);
while ($rand == $num)
{
$rand = mt_rand(1, $range);
}
return $rand;
}
}
}
私有函数randomWithProbability($chance,$num,$range=false)
{
/*首先生成一个数字0和1,看看这个数字是否在概率范围内*/
$rand=$this->getRandomFloatValue(0,1);
如果($rand您正在寻找的基本算法:
- 将所有概率相加,确定最大值
- 选择一个介于0和1之间的随机数,并将其乘以最大值
- 查找与该值对应的条目
示例代码:
<?php
// create some weighted sample data (id => weight)
$samples = array(
'a' => 0.001,
'b' => 0.004,
'c' => 0.006,
'd' => 0.05,
'e' => 0.01,
'f' => 0.015,
'g' => 0.1
);
class Accumulator {
function __construct($samples) {
// accumulate all samples into a cumulative amount (a running total)
$this->acc = array();
$this->ids = array();
$this->max = 0;
foreach($samples as $k=>$v) {
$this->max += $v;
array_push($this->acc, $this->max);
array_push($this->ids, $k);
}
}
function pick() {
// selects a random number between 0 and 1, increasing the multiple here increases the granularity
// and randomness; it should probably at least match the precision of the sample data (in this case 3 decimal digits)
$random = mt_rand(0,1000)/1000 * $this->max;
for($i=0; $i < count($this->acc); $i++) {
// looks through the values until we find our random number, this is our seletion
if( $this->acc[$i] >= $random ) {
return $this->ids[$i];
}
}
throw new Exception('this is mathematically impossible?');
}
private $max; // the highest accumulated number
private $acc; // the accumulated totals for random selection
private $ids; // a list of the associated ids
}
$acc = new Accumulator($samples);
// create a results object to test our random generator
$results = array_fill_keys(array_keys($samples), 0);
// now select some data and test the results
print "picking 10000 random numbers...\n";
for($i=0; $i < 10000; $i++) {
$results[ $acc->pick() ]++;
}
// now show what we found out
foreach($results as $k=>$v) {
print "$k picked $v times\n";
}
使用此示例运行相同的代码:
// samples with even weight
$samples = array(
'a' => 0.1,
'b' => 0.1,
'c' => 0.1,
'd' => 0.1
);
产生以下结果:
> php.exe rand.php
picking 10000 random numbers...
a picked 52 times
b picked 198 times
c picked 378 times
d picked 2655 times
e picked 543 times
f picked 761 times
g picked 5413 times
> php.exe rand.php
picking 10000 random numbers...
a picked 2520 times
b picked 2585 times
c picked 2511 times
d picked 2384 times
我会让说PHP的人写答案(可能是你),但总体思路是这样的。你要做的是创建一个包含累积分布的数组,即概率的连续总和。然后你选择兰德不超过累积分布的最大指数。你的答案有道理,但同时也没有。我不明白选择最大指数会有什么效果给我一个概率更高的随机数“我想检索一个介于1和6之间的随机数,但是…11比1的概率更高”我想你可能在这里有不必要的信息,或者你有一个错误…可能是重复的,或者,因为你正在遍历整个数组,你可以只保留一个变量,在遍历数组时跟踪累积。谢谢,这帮助了Looot,这比我预期的要多。我感谢你的帮助,它成功了,它的解决方案也很完美。感谢alotnp;我的PHP技能停滞不前,这很有趣:)@jswolf19如果你认为它可以优化,请提交一个答案;我会给它打分!我怀疑500个条目会有很大的不同,但你可以进行二进制搜索,因为你知道累积的数量总是在增加^_~