在PHP中按权重生成随机结果?
我知道如何在PHP中生成一个随机数,但假设我想要一个介于1-10之间的随机数,但我想要更多的3,4,5,然后是8,9,10。这怎么可能?我会发布我尝试过的东西,但老实说,我甚至不知道从哪里开始 基本上:在PHP中按权重生成随机结果?,php,random,Php,Random,我知道如何在PHP中生成一个随机数,但假设我想要一个介于1-10之间的随机数,但我想要更多的3,4,5,然后是8,9,10。这怎么可能?我会发布我尝试过的东西,但老实说,我甚至不知道从哪里开始 基本上: 将所有数字的权重相加 选择一个小于该值的随机数 按顺序减去权重,直到结果为负数,如果为负数,则返回该数字 对于一个始终向刻度一端倾斜的有效随机数: 选择0到1之间的连续随机数 升到γ的幂,使其偏置。1是未加权的,越低给出的数字越高,反之亦然 按比例缩放到所需范围,并舍入到整数 例如,在PHP
对于一个始终向刻度一端倾斜的有效随机数:
- 选择0到1之间的连续随机数
- 升到γ的幂,使其偏置。1是未加权的,越低给出的数字越高,反之亦然
- 按比例缩放到所需范围,并舍入到整数
/**
* weighted_random_simple()
* Pick a random item based on weights.
*
* @param array $values Array of elements to choose from
* @param array $weights An array of weights. Weight must be a positive number.
* @return mixed Selected element.
*/
function weighted_random_simple($values, $weights){
$count = count($values);
$i = 0;
$n = 0;
$num = mt_rand(1, array_sum($weights));
while($i < $count){
$n += $weights[$i];
if($n >= $num){
break;
}
$i++;
}
return $values[$i];
}
/**
*加权随机简单()
*根据权重选择一个随机项。
*
*@param array$values可供选择的元素数组
*@param array$weights一个权重数组。权重必须是正数。
*@return混合选定元素。
*/
函数加权随机简单($value,$weights){
$count=计数($value);
$i=0;
$n=0;
$num=mt_rand(1,数组和($weights));
而($i<$count){
$n+=$weights[$i];
如果($n>=$num){
打破
}
$i++;
}
返回$value[$i];
}
既然我使用了IainMH的解决方案,我不妨分享我的PHP代码:
朴素而公平。
只需复制/粘贴并测试它
/**
* getRandomWeightedElement()
* Utility function for getting random values with weighting.
* Pass in an associative array, such as array('A'=>5, 'B'=>45, 'C'=>50)
* An array like this means that "A" has a 5% chance of being selected, "B" 45%, and "C" 50%.
* The return value is the array key, A, B, or C in this case. Note that the values assigned
* do not have to be percentages. The values are simply relative to each other. If one value
* weight was 2, and the other weight of 1, the value with the weight of 2 has about a 66%
* chance of being selected. Also note that weights should be integers.
*
* @param array $weightedValues
*/
function getRandomWeightedElement(array $weightedValues) {
$rand = mt_rand(1, (int) array_sum($weightedValues));
foreach ($weightedValues as $key => $value) {
$rand -= $value;
if ($rand <= 0) {
return $key;
}
}
}
/**
*收益加权概率
*@param(数组)prob=>item
*@返回键
*/
函数权重和($stream){
$pos=mt_rand(1,数组和(数组键($stream)));
$em=0;
foreach($k=>v){
$em+=$k;
如果($em>=$pos)
返回$v;
}
}
$item['30']=“我比每个人都有更多的机会:”;
$item['10']=“我有很好的机会”;
$item['1']=“我很难出现…”;
对于基于@Allain/的($i=1;$i),我用PHP编写了这个快速函数。如果要使用非整数加权,则必须修改它
use function \nspl\a\pairs;
use function \nspl\rnd\weightedChoice;
$weights = pairs(array(
1 => 10,
2 => 15,
3 => 15,
4 => 15,
5 => 15,
6 => 10,
7 => 5,
8 => 5,
9 => 5,
10 => 5
));
$number = weightedChoice($weights);
/**
*getRandomWeightedElement()
*用于获取带有权重的随机值的实用函数。
*传入关联数组,例如数组('A'=>5,'B'=>45,'C'=>50)
*这样的数组意味着“A”被选中的几率为5%,“B”为45%,而“C”为50%。
*在本例中,返回值是数组键A、B或C
*不必是百分比。这些值只是彼此相对的。如果一个值
*权重为2,另一个权重为1,权重为2的值约为66%
*被选中的机会。还要注意权重应该是整数。
*
*@param数组$weightedValues
*/
函数getRandomWeightedElement(数组$weightedValues){
$rand=mt_rand(1,(int)数组_和($weightedValues));
foreach($key=>$value的加权值){
$rand-=$value;
if($rand您可以使用from。它接受对(项、权重)的列表,以便能够处理不能作为数组键的项。您可以使用函数将数组(项=>权重)
转换为所需的格式
/**
* @param array $weightedValues
* @return string
*/
function getRandomWeightedElement(array $weightedValues)
{
$array = array();
foreach ($weightedValues as $key => $weight) {
$array = array_merge(array_fill(0, $weight, $key), $array);
}
return $array[array_rand($array)];
}
在本例中,2-5的出现频率是7-10的3倍。我刚刚轻松发布了一个
它基于和answers中提到的相同算法,并针对速度进行了优化,针对均匀分布进行了单元测试,并支持任何PHP类型的元素
使用它很简单。请实例化它:
$picker=newbrick\Random\RandomPicker();
然后将元素添加为加权值数组(仅当元素是字符串或整数时):
$picker->addElements([
‘foo’=>25,
'bar'=>50,
‘baz’=>100
]);
或者使用对addElement()
的单独调用。此方法支持任何类型的PHP值作为元素(字符串、数字、对象等),而不是数组方法:
$picker->addElement($object1,$weight1);
$picker->addElement($object2,$weight2);
然后得到一个随机元素:
$element=$picker->getRandomElement();
获取其中一个元素的概率取决于其关联的权重。唯一的限制是权重必须是整数
foreach ($values as $amount) {
$total += $amount;
}
$rand = mt_rand(0, $total-1);
foreach ($values as $amount) {
$currentTotal += $amount;
if ($rand => $currentTotal) {
$bucket++;
}
else {
break;
}
}
return $bucket;
getRandomWeightedElement(数组('A'=>10,'B'=>90));
这是一个非常简单的方法。如何获取随机加权元素。我填充数组变量$key。我获取数组$key到数组$weight x。然后,使用数组\u rand到数组。我有随机值;)。函数getBucketFromWeights($value){
$total=$currentTotal=$bucket=0
$values_and_weights=array(
1=>1,
2=>1,
3=>2,
4=>2,
5=>2,
6=>1,
7=>1,
8=>1,
9=>1,
10=>1
);
}
我根据这里的答案修改了这个
在我写了这篇文章之后,我看到其他人有了一个更加优雅的答案。他。这一页上的许多答案似乎使用了数组膨胀、过度迭代、库或难以阅读的过程。当然,每个人都认为自己的宝宝是最可爱的,但我诚实地认为我的方法是精简、简单和易于阅读/修改的…
根据操作,我将创建一个从1到10的值数组(声明为键),其中3、4和5的权重是其他值(声明为值)的两倍
如果您只打算进行一次随机选择,并且/或者您的阵列相对较小*(请自行进行基准测试),这可能是您的最佳选择:
// Declare new array using array_walk one-liner:
array_walk($values_and_weights,function($v,$k)use(&$limits_and_values,&$x){$limits_and_values[$x+=$v]=$k;});
//Alternative declaration method - 4-liner, foreach() loop:
/*$x=0;
foreach($values_and_weights as $val=>$wgt){
$limits_and_values[$x+=$wgt]=$val;
}*/
var_export($limits_and_values);
这种方法不涉及数组修改,可能不需要迭代整个数组(但可能需要)
另一方面,如果您要在阵列上进行多个随机选择,并且/或者您的阵列足够大*(请自行进行基准测试,以确保
foreach ($values as $amount) {
$total += $amount;
}
$rand = mt_rand(0, $total-1);
foreach ($values as $amount) {
$currentTotal += $amount;
if ($rand => $currentTotal) {
$bucket++;
}
else {
break;
}
}
return $bucket;
$values_and_weights=array(
1=>1,
2=>1,
3=>2,
4=>2,
5=>2,
6=>1,
7=>1,
8=>1,
9=>1,
10=>1
);
$pick=mt_rand(1,array_sum($values_and_weights));
$x=0;
foreach($values_and_weights as $val=>$wgt){
if(($x+=$wgt)>=$pick){
echo "$val";
break;
}
}
// Declare new array using array_walk one-liner:
array_walk($values_and_weights,function($v,$k)use(&$limits_and_values,&$x){$limits_and_values[$x+=$v]=$k;});
//Alternative declaration method - 4-liner, foreach() loop:
/*$x=0;
foreach($values_and_weights as $val=>$wgt){
$limits_and_values[$x+=$wgt]=$val;
}*/
var_export($limits_and_values);
array (
1 => 1,
2 => 2,
4 => 3,
6 => 4,
8 => 5,
9 => 6,
10 => 7,
11 => 8,
12 => 9,
13 => 10,
)
// $x (from walk/loop) is the same as writing: end($limits_and_values); $x=key($limits_and_values);
$pick=mt_rand(1,$x); // pull random integer between 1 and highest limit/key
while(!isset($limits_and_values[$pick])){++$pick;} // smallest possible loop to find key
echo $limits_and_values[$pick]; // this is your random (weighted) value