Сортировка массива с использованием вероятностного распределения

#php #arrays #math #probability

#php #массивы #математика #вероятность

Вопрос:

Массив должен быть отсортирован от высокого к низкому по его значениям.

 <?php
$items = array(
  1 => f(1),
  2 => f(2),
  3 => f(3),
  4 => f(4),
  5 => f(5),
);
?>
  

После сортировки я смотрю, какой элемент 1, 2, 3, 4, 5 является первым. Я пробую это снова, и снова, и снова.
Впоследствии

  • 5 должно быть первым элементом в пять раз больше, чем 1
  • 4 должно быть первым элементом в четыре раза больше, чем 1
  • 3 должно быть первым элементом в три раза больше, чем 1
  • 4 должно быть первым элементом в два раза больше, чем 2

Одна идея заключается

 <?php
function f(key) {
  return key / random();
}
?>
  

что для 1’000’000 попыток привело к

 key | times on top | ratio with key one | expected ratio
---- -------------- -------------------- ---------------
 5  |      374'365 | 6.75               | 5
 4  |      267'863 | 4.83               | 4
 3  |      185'707 | i am so lazy ...   | 3
 2  |      116'618 |                    | 2
 1  |       55'447 | 1                  | 1
  

Для меня это выглядит странно, но, возможно

  • есть простая проблема с f?
  • есть лучший f?


Моя реализация:

 <?php

abstract class Test {

  private $result;

  protected abstract function f($x);

  protected function iteration() {
    $values = array(
      1 => $this->f(1),
      2 => $this->f(2),
      3 => $this->f(3),
      4 => $this->f(4),
      5 => $this->f(5),
    );

    arsort($values);

    $top = key($values);

    if (!isset($this->result[$top])) {
      $this->result[$top] = 1;
    } else {
      $this->result[$top]  ;
    }
  }

  public function run($iterations) {
    $this->result = array();
    for($i = 0; $i < $iterations; $i  ) {
      $this->iteration();
    }
    arsort($this->result);
    return $this->resu<
  }
}

class MyTest extends Test {
  protected function f($x) {
    return $x / rand();
  }
}

$test = new MyTest();
$result = $test->run(1000 * 1000);
print_r($result);
printf("Ratio of key 5 to 1, which should be 5: %fn", $result[5] / $result[1]);

?>
  

Я перепробовал миллиард раундов. Но опять же соотношение равно 6,75 — весь смысл в том, почему это не пять?


Результаты для

 <?php
class BetterRandomGeneratorTest extends Test {
  protected function f($x) {
    return $x / mt_rand();
  }
}
?>
  

являются

 Array
(
  [5] => 3742816
  [4] => 2674352
  [3] => 1861444
  [2] => 1168333
  [1] => 553055
)
Ratio of key 5 to 1: 6.767529
  

Комментарии:

1. Строгий закон больших чисел гласит, что это правда. Сделайте миллиард попыток.

2. Что вы ищете?! Я не понимаю, пытаетесь ли вы понять, почему / как, или вам нужна помощь в реализации того, что вы пытаетесь сделать… Попробуйте немного прояснить свой вопрос.

3. Я согласен. Чего f(x) предполагается достичь?

4. Попробуйте другие генераторы случайных чисел, такие как mt_rand, и посмотрите, получите ли вы лучшие результаты.

5. @Frits van Campen: Добавил результаты для mt_random к вопросу

Ответ №1:

Вот простое f, которое это сделает.

 function f(key) {
  $x = 0;
  for($i = 0; $i < $key; $i  ) {
    $y = random();
    if ($x < $y) {
      $x = $y;
    }
  }
  return $x;
}
  

Это гарантированно сработает, потому что максимальным с равной вероятностью будет любое из 15 выбранных случайных чисел, и в 1/3 случаев это число будет находиться в f(5) , по сравнению с 1/15 для f(1) .

Что касается того, что было не так с вашим f , это довольно просто. Ваше решение обладает хорошей симметрией ровно в 80% случаев f(1) < f(5) . Однако f(1) имеет тенденцию быть больше, чем f(5) когда f(1) больше среднего и f(5) меньше среднего. То же самое для f(2) , f(3) и f(4) . Однако необычно, чтобы все f(2), ... f(5) были маленькими сразу. Это приводит к тому, что корреляции, которые вызывают f(1) наибольшее значение, встречаются реже, чем вы наивно думаете. Наоборот, корреляции, как правило, проявляются в пользу f(5) чаще, чем вы могли бы наивно подумать.

Если вы хотите вычислить точные вероятности каждого числа, выходящего сверху, не должно быть слишком сложно вычислить точные ответы с интеграцией. Идея заключается в том, что вы интегрируете от 0 до 1 вероятность того, что, если это было значением random() для f(i) этого f(i) , оно является максимальным. (Так, например, для 5 вы бы интегрировали, (1-x/5)(1-x/4)(1-x/3)(1-x/2) в то время как для 1 вы бы интегрировали функцию, которая равна 0, если random() больше 0.2, а в противном случае равна (1-2x)(1-3x)(1-4x)(1-5x) .) Выражения будут сложными, и соотношения не приведут к хорошим ответам.

Комментарии:

1. Что такое $ iterations и куда входит $ key? — Объяснение очень приятное.

2. @Niklas: Это было неправильное имя переменной. Это должен был быть $key. Исправлено.