복붙노트

PHP에서 가중치로 무작위 결과를 생성 하시겠습니까?

PHP

PHP에서 가중치로 무작위 결과를 생성 하시겠습니까?

PHP에서 임의의 숫자를 생성하는 방법을 알고 있지만 1-10 사이의 임의의 숫자를 원하지만 3, 4, 5, 8,9,10을 더 원한다고 말할 수 있습니다. 이것이 어떻게 가능한지? 나는 내가 시도했지만 정직하게 글을 올릴 것이고, 어디서부터 시작해야할지조차 모른다.

해결법

  1. ==============================

    1.@ Allain의 응답 / 링크를 기반으로 PHP에서이 빠른 기능을 수행했습니다. 비 정수 가중치를 사용하려면이 값을 수정해야합니다.

    @ 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;
          }
        }
      }
    
  2. ==============================

    2.규모의 한쪽 끝을 향해 지속적으로 왜곡 된 효율적인 난수의 경우 :

    규모의 한쪽 끝을 향해 지속적으로 왜곡 된 효율적인 난수의 경우 :

    예. PHP (테스트되지 않음) :

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

    3.꽤 좋은 튜토리얼이 있습니다.

    꽤 좋은 튜토리얼이 있습니다.

    원래:

  4. ==============================

    4.순진한 해킹은 다음과 같은 목록이나 배열을 만드는 것입니다.

    순진한 해킹은 다음과 같은 목록이나 배열을 만드는 것입니다.

    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

    그런 다음 무작위로 선택하십시오.

  5. ==============================

    5.이 튜토리얼에서는 여러 가지 잘라 내기 및 붙여 넣기 솔루션을 사용하여 PHP를 통해 안내합니다. 이 루틴은 아래 주석의 결과로 해당 페이지에서 찾을 수있는 것에서 약간 수정됩니다.

    이 튜토리얼에서는 여러 가지 잘라 내기 및 붙여 넣기 솔루션을 사용하여 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]; 
    }
    
  6. ==============================

    6.평범하고 공정하다. 복사 / 붙여 넣기를하고 테스트하십시오.

    평범하고 공정하다. 복사 / 붙여 넣기를하고 테스트하십시오.

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

    편집 : 끝에 대괄호가 추가되었습니다.

  7. ==============================

    7.비표준 PHP 라이브러리의 weightedChoice를 사용할 수 있습니다. 배열 키가 될 수없는 항목으로 작업 할 수있는 쌍 (항목, 가중치) 목록을 허용합니다. 쌍 함수를 사용하여 배열 (항목 => 가중치)을 필요한 형식으로 변환 할 수 있습니다.

    비표준 PHP 라이브러리의 weightedChoice를 사용할 수 있습니다. 배열 키가 될 수없는 항목으로 작업 할 수있는 쌍 (항목, 가중치) 목록을 허용합니다. 쌍 함수를 사용하여 배열 (항목 => 가중치)을 필요한 형식으로 변환 할 수 있습니다.

    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 배 더 자주 나타납니다.

  8. ==============================

    8.IainMH의 솔루션을 사용했기 때문에 PHP 코드를 공유 할 수도 있습니다.

    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>
    
  9. ==============================

    9.

    /**
     * @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를 채 웁니다. $ weight x를 배열하기 위해 $ key를 얻는다. 그런 다음 배열에 array_rand를 사용하십시오. 그리고 난 임의의 가치가있다;).

  10. ==============================

    10.방금 클래스를 릴리스하여 쉽게 가중치 정렬을 수행했습니다.

    방금 클래스를 릴리스하여 쉽게 가중치 정렬을 수행했습니다.

    이것은 Brad 's와 Allain의 대답에서 언급 한 것과 같은 알고리즘을 기반으로하며, 속도에 최적화되어 있고, 균일 한 배포를 위해 단위 테스트를 거쳤으며 모든 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();
    

    요소 중 하나를 얻는 확률은 관련 가중치에 따라 다릅니다. 유일한 제한은 가중치가 정수 여야한다는 것입니다.

  11. ==============================

    11.function getBucketFromWeights ($ values) {     $ total = $ currentTotal = $ bucket = 0;

    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;
    

    }

    여기서 답을 수정했습니다. 사용자가 정의한 가중치로 임의의 요소를 선택했습니다.

    내가 이것을 쓴 후에 나는 다른 누군가가 훨씬 더 우아한 답을 얻는 것을 보았다. 그 사람 그는.

  12. ==============================

    12.이 페이지의 많은 답변은 배열 확장, 과도한 반복, 라이브러리 또는 읽기 어려운 프로세스를 사용하는 것 같습니다. 물론, 모두가 자신의 아기가 가장 귀여웠다고 생각하지만 솔직히 내 접근 방식이 단순하고 읽기 쉽고 / 수정하기 쉽다고 생각합니다 ...

    이 페이지의 많은 답변은 배열 확장, 과도한 반복, 라이브러리 또는 읽기 어려운 프로세스를 사용하는 것 같습니다. 물론, 모두가 자신의 아기가 가장 귀여웠다고 생각하지만 솔직히 내 접근 방식이 단순하고 읽기 쉽고 / 수정하기 쉽다고 생각합니다 ...

    OP별로, (값으로 선언 된) 다른 값의 2 배의 무게를 갖는 3, 4 및 5와 함께 1에서 10까지의 값 배열 (키로 선언 됨)을 생성합니다.

    $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 ()은 매우 빠르며 while 루프의 최대 isset () 호출 수는 배열의 최대 가중치 (한도와 혼동하지 말아야 함) 만큼일 수 있기 때문에이 접근법은 훌륭합니다. 이 경우 최대 반복 = 2!

    이 접근법은 전체 배열을 ITERATE 할 필요가 없다.

  13. from https://stackoverflow.com/questions/445235/generating-random-results-by-weight-in-php by cc-by-sa and MIT license