php 在PHP中按重量生成随机结果?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/445235/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 22:46:12  来源:igfitidea点击:

Generating random results by weight in PHP?

phprandom

提问by kyct

I know how to generate a random number in PHP but lets say I want a random number between 1-10 but I want more 3,4,5's then 8,9,10's. How is this possible? I would post what I have tried but honestly, I don't even know where to start.

我知道如何在 PHP 中生成一个随机数,但可以说我想要一个 1-10 之间的随机数,但我想要更多的 3、4、5 然后是 8、9、10。这怎么可能?我会发布我尝试过的内容,但老实说,我什至不知道从哪里开始。

回答by Brad

Based on @Allain's answer/link, I worked up this quick function in PHP. You will have to modify it if you want to use non-integer weighting.

基于@Allain 的回答/链接,我在 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;
      }
    }
  }

回答by bobince

For an efficient random number skewed consistently towards one end of the scale:

对于一个始终向尺度一端倾斜的有效随机数:

  • Choose a continuous random number between 0..1
  • Raise to a power γ, to bias it. 1 is unweighted, lower gives more of the higher numbers and vice versa
  • Scale to desired range and round to integer
  • 选择一个介于 0..1 之间的连续随机数
  • 提高到 γ 幂,以对其进行偏置。1 是未加权的,较低的给出更多的较高的数字,反之亦然
  • 缩放到所需范围并四舍五入到整数

eg. in PHP (untested):

例如。在 PHP 中(未经测试):

function weightedrand($min, $max, $gamma) {
    $offset= $max-$min+1;
    return floor($min+pow(lcg_value(), $gamma)*$offset);
}
echo(weightedrand(1, 10, 1.5));

回答by Allain Lalonde

There's a pretty good tutorial for you.

有一个很好的教程给你

Basically:

基本上:

  1. Sum the weights of all the numbers.
  2. Pick a random number less than that
  3. subtract the weights in order until the result is negative and return that number if it is.
  1. 将所有数字的权重相加。
  2. 选择一个小于这个的随机数
  3. 按顺序减去权重,直到结果为负,如果是则返回该数字。

回答by Iain Holder

The naive hack for this would be to build a list or array like

对此的天真黑客将是构建一个列表或数组,如

1, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 10

1, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 10

And then select randomly from that.

然后从中随机选择。

回答by Brad Parks

This tutorialwalks you through it, in PHP, with multiple cut and paste solutions. Note that this routine is slightly modified from what you'll find on that page, as a result of the comment below.

本教程将引导您在 PHP 中使用多种剪切和粘贴解决方案。请注意,由于下面的评论,此例程与您在该页面上找到的内容略有不同。

A function taken from the post:

从帖子中获取的功能:

/**
 * 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]; 
}

回答by Luká? K?í?

/**
 * @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)];
}

getRandomWeightedElement(array('A'=>10, 'B'=>90));

getRandomWeightedElement(array('A'=>10, 'B'=>90));

This is very easy method. How get random weighted element. I fill array variable $key. I get $key to array $weight x. After that, use array_rand to array. And I have random value ;).

这是非常简单的方法。如何获得随机加权元素。我填充数组变量 $key。我得到 $key 数组 $weight x。之后,使用 array_rand 进行排列。我有随机值;)。

回答by Nick Olszanski

Plain and fair. Just copy/paste and test it.

朴实而公正。只需复制/粘贴并测试它。

/**
 * Return weighted probability
 * @param (array) prob=>item 
 * @return key
 */
function weightedRand($stream) {
    $pos = mt_rand(1,array_sum(array_keys($stream)));           
    $em = 0;
    foreach ($stream as $k => $v) {
        $em += $k;
        if ($em >= $pos)
            return $v;
    }

}

$item['30'] = 'I have more chances than everybody :]';
$item['10'] = 'I have good chances';
$item['1'] = 'I\'m difficult to appear...';

for ($i = 1; $i <= 10; $i++) {
    echo weightedRand($item).'<br />';
}

Edit: Added missing bracket at the end.

编辑:最后添加了缺少的括号。

回答by Ihor Burlachenko

You can use weightedChoicefrom Non-standard PHP library. It accepts a list of pairs (item, weight) to have the possibility to work with items that can't be array keys. You can use pairsfunction to convert array(item => weight)to the needed format.

您可以使用来自非标准 PHP 库的weightedChoice。它接受一个对(物品、重量)的列表,以便有可能处理不能是数组键的物品。您可以使用pairs函数转换为所需的格式。array(item => weight)

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);

In this example, 2-5 will appear 3 times more often than 7-10.

在本例中,2-5 的出现频率是 7-10 的 3 倍。

回答by Benjamin

I just released a class to perform weighted sortingeasily.

我刚刚发布了一个类来轻松执行加权排序

It's based on the same algorithm mentioned in Brad'sand Allain'sanswers, and is optimized for speed, unit-tested for uniform distribution, and supports elements of any PHP type.

它基于BradAllain 的答案中提到的相同算法,并针对速度进行了优化,针对均匀分布进行了单元测试,并支持任何 PHP 类型的元素。

Using it is simple. Instantiate it:

使用它很简单。实例化它:

$picker = new Brick\Random\RandomPicker();

Then add elements as an array of weighted values (only if your elements are strings or integers):

然后将元素添加为加权值数组(仅当您的元素是字符串或整数时):

$picker->addElements([
    'foo' => 25,
    'bar' => 50,
    'baz' => 100
]);

Or use individual calls to addElement(). This method supports any kind of PHP values as elements (strings, numbers, objects, ...), as opposed to the array approach:

或者使用单独调用addElement(). 与数组方法相反,此方法支持任何类型的 PHP 值作为元素(字符串、数字、对象等):

$picker->addElement($object1, $weight1);
$picker->addElement($object2, $weight2);

Then get a random element:

然后得到一个随机元素:

$element = $picker->getRandomElement();

The probability of getting one of the elements depends on its associated weight. The only restriction is that weights must be integers.

获得其中一个元素的概率取决于其相关的权重。唯一的限制是权重必须是整数。

回答by degenerate

Since I used IainMH's solution, I may as well share my PHP code:

既然用了IainMH的解决方案,不妨分享一下我的PHP代码:

<pre><?php

// Set total number of iterations
$total = 1716;

// Set array of random number
$arr = array(1, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5);
$arr2 = array(0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 5);

// Print out random numbers
for ($i=0; $i<$total; $i++){

    // Pick random array index
    $rand = array_rand($arr);
    $rand2 = array_rand($arr2);

    // Print array values
    print $arr[$rand] . "\t" . $arr2[$rand2] . "\r\n";

}

?></pre>