我知道如何在PHP中生成一个随机数,但可以说我想要一个1-10之间的随机数,但我想要更多的3,4,5然后是8,9,10。这怎么可能?我会张贴我尝试过的,但老实说,我甚至不知道从哪里开始。在PHP中通过权重生成随机结果?
回答
对此的幼稚黑客将建立一个列表或阵列状
1,2,3,3,3,3,3,4,4,4,4,4,4,5, 5,5,5,6,6,7,7,7,8,8,9,9,10,10
然后从中随机选择。
此外,这没有先前的答案的内存开销(建立另一个阵列与所需的分布,并从中随机选择) – 2009-01-15 00:55:36
这是非天真的黑客攻击。 :-) – 2009-01-15 01:06:56
为了有效的随机数一致偏向规模的一端:
- 选择0..1
- 抬起之间的功率γ的连续随机数,以将其偏置。图1是未加权的,低级提供了更多的数字较高,反之亦然
- 缩放到期望的范围内和圆整数
例如。在PHP(未经测试):
function weightedrand($min, $max, $gamma) {
$offset= $max-$min+1;
return floor($min+pow(lcg_value(), $gamma)*$offset);
}
echo(weightedrand(1, 10, 1.5));
我爱你的答案。请看看我的问题(下面的链接)。我很乐意听取您的意见,并将其扩展。 http://stackoverflow.com/questions/4030427/generate-random-weighted-value – 2010-10-27 06:25:52
This tutorial指导您完成它,在PHP中,有多个剪切和粘贴的解决方案。请注意,由于下面的注释,此例程与您在该页面上找到的内容略有不同。
从后拍摄的功能:
/**
* 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];
}
,因为我用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>
平原和公平。 只需复制/粘贴并测试它。
/**
* 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 />';
}
编辑:在结尾处添加缺少的括号。
基于@ Allain的answer/link,我使用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;
}
}
}
您可以使用weightedChoice从Non-standard PHP library。它接受配对列表(物品,重量),以便可以使用不能成为数组键的物品。您可以使用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);
在这个例子中,2-5会比7-10多3倍。
我刚刚发布class to perform weighted sorting很容易。
它基于与Brad's和Allain's中提到的算法相同的算法,并针对速度进行了优化,单元测试均匀分布,并支持任何PHP类型的元素。
使用它很简单。实例吧:
$picker = new Brick\Random\RandomPicker();
然后添加元素的加权值的数组(仅当您的元素是字符串或整数):
$picker->addElements([
'foo' => 25,
'bar' => 50,
'baz' => 100
]);
或者使用个人来电addElement()
。此方法支持任何种类的PHP值作为元素(字符串,数字,对象,...),而不是在阵列的方法:
$picker->addElement($object1, $weight1);
$picker->addElement($object2, $weight2);
然后得到一个随机元素:
$element = $picker->getRandomElement();
的获取其中一个元素的可能性取决于其相关的权重。唯一的限制是权重必须是整数。
/**
* @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));
这是非常简单的方法。如何获得随机加权元素。我填充数组变量$ key。我得到$ key给数组$ weight x。之后,使用array_rand到数组。我有随机值;)。
function getBucketFromWeights($ values){ $ total = $ currentTotal = $ bucket = 0;
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;
}
我哎从这里Picking random element by user defined weights
答案我写了这个之后,我看到别人有一个更优雅的回答修改此。他他是他。
本页面上的许多答案似乎都使用数组膨胀,过度迭代,库或难以阅读的过程。当然,每个人都认为自己的宝宝是最可爱的,但我真的认为我的方法是精简,简单易读/修改...
根据OP,我将创建一个值数组(声明为键)从1到10,其中3,4和5的权重是其他值的两倍(声明为值)。
$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;
}
}
这种方法不涉及数组修改,可能不需要迭代整个数组(但可能)。
在另一方面,如果你要使阵列上的多个随机选择和/或您的阵列足够大*(做你自己的基准测试,以确保),重组的阵列可能更好。
用于生成新的阵列将越来越对齐在存储器中的成本:
- 阵列尺寸的增加和
- 数随机选择的增加。
新阵列要求用每个值的“限制”替换“重量”,方法是将前一个元素的权重添加到当前元素的权重。
然后翻转数组,使极限是数组键,值是数组值。 逻辑是:所选值将具有> = $ pick的最低限制。
// 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,
)
我们生成随机$pick
和选择值:
// $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
这种做法是辉煌的,因为isset()
非常快,最大数量isset()
while循环中的调用只能与阵列中的最大权重(不要与极限混淆)一样多。对于这种情况,最大迭代次数= 2!
这种方法从来不需要遍历整个数组
- 1. 通过随机字符生成生成随机名字太慢
- 2. 通过Javascript/HTML生成随机链接
- 3. R中的加权随机数生成
- 4. 重现C++ 11随机生成器的相同结果
- 5. 生成一个随机数,偏差结果为PHP
- 6. 在PHP中生成随机值
- 7. 在php中生成随机数字
- 8. 在php中生成随机数
- 9. PHP生成随机密码
- 10. 随机ID /数生成PHP
- 11. 过滤随机结果
- 12. 如何用C#中的权重编写随机数生成器?
- 13. 加权随机数生成C#
- 14. 生成,评估,然后在Ruby中重新生成随机数
- 15. 通过伪随机朴素随机数生成器生成随机数序列的正确方法
- 16. 随机生成的PHP IV未在IOS
- 17. 随机生成图中的“连通性”
- 18. JavaScript:if语句正在改变随机生成器的结果吗?
- 19. 通过列表中的值随机生成一组人群
- 20. 通过R中的随机数生成查找分布
- 21. 随机生成3x3x3“块”大结构
- 22. 通过Hudson生成Jmeter结果为几次试验的结果
- 23. 随机数不会产生随机结果
- 24. 随机结果集成测试
- 25. PHP代码生成事件在1到20秒之间的随机随机重复中重复
- 26. 随机数生成在PySpark
- 27. 如何重用随机结果?
- 28. 随机串生成 - 两个生成一个又一个给相同的结果
- 29. PHP:随机结果每天一次,
- 30. 生成随机骰子卷和测量结果的频率
完全正确。创建一个列表,其中加权的数字以您想要的比例加权(如果可能,可以使用其他函数创建列表),然后从列表中随机选择一个项目。 – Ross 2009-01-15 00:51:59
唯一的缺点是,如果你希望数字1的可能性比其他数字高1万亿倍,那么你需要一个1万亿以上的元素。 – 2009-01-15 00:53:17
@Allain Lalonde哦相当。它不会扩展,但它非常简单,可能足以满足OP的需求。 – 2009-01-15 00:56:34