Как добавить «веса» в таблицу MySQL и выбрать случайные значения в соответствии с ними? - PullRequest
3 голосов
/ 30 ноября 2009

Я хочу создать таблицу, в которой каждая строка будет содержать какой-нибудь вес. Затем я хочу выбрать случайные значения с вероятностью, равной (вес этой строки) / (вес всех строк). Например, имея 5 рядов с весами 1,2,3,4,5 из 1000, я получу примерно 1/15 * 1000 = 67 раз в первом ряду и т. Д.

Таблица заполняется вручную. Тогда я возьму случайное значение из этого. Но я хочу иметь возможность изменять вероятности на стадии заполнения.

Ответы [ 6 ]

3 голосов
/ 30 ноября 2009

Я нашел этот хороший маленький алгоритм в Quod Libet. Возможно, вы могли бы перевести его на какой-то процедурный SQL.

function WeightedShuffle(list of items with weights):
  max_score ← the sum of every item’s weight
  choice ← random number in the range [0, max_score)
  current ← 0
  for each item (i, weight) in items:  
    current ← current + weight  
    if current ≥ choice or i is the last item:  
      return item i
1 голос
/ 01 декабря 2009

Я не специалист по теории вероятностей, но при условии, что у вас есть столбец с именем WEIGHT, как насчет

select FIELD_1, ... FIELD_N, (rand() * WEIGHT) as SCORE
  from YOURTABLE
 order by SCORE
 limit 0, 10

Это даст вам 10 записей, но вы, конечно, можете изменить условие лимита.

1 голос
/ 30 ноября 2009

Лучший из возможных сценариев (если я правильно понимаю ваш вопрос) - это настроить таблицу так, как вы обычно это делаете, а затем добавить два столбца с INT.

  • Столбец 1: Вес - Этот столбец будет содержать значение вашего веса, изменяющееся от -X до + X, где X является наибольшим значением, которое вы хотите иметь в качестве веса (IE: X = 100, от -100 до 100). Это значение заполняется, чтобы придать строке фактический вес и увеличить или уменьшить вероятность его появления.

  • Столбец 2: * Количество ** - В этом столбце будет содержаться счетчик количества попыток появления этой строки. Этот столбец необходим, только если вы хотите использовать справедливое взвешивание. Справедливое взвешивание предотвращает появление одного ряда. (IE: если у вас есть одна строка, взвешенная на 100, а другая на 2, строка с 100 всегда будет отображаться, этот столбец позволит весу 2 быть более «ценным», так как вы получите больше результатов с весом 100). Этот столбец следует увеличивать на 1 каждый раз, когда извлекается результат строки, но позже вы можете сделать логику более продвинутой, добавив вес и т. Д.

  • Логика: - Теперь это действительно просто, ваш запрос просто должен запросить все строки, как обычно, а затем сделать дополнительный выбор (вы можете изменить логику здесь на что угодно) берет вес и вычитает количество и порядок по этому столбцу.

Конечным результатом должна быть таблица, в которой ваши веса будут отображаться чаще, до определенной точки, где система будет равномерно распределяться (пропустите столбец 2), и у вас будет система, которая всегда будет возвращать одинаковые веса порядок, если вы не смещаете основание запроса (IE: LIMIT [RANDOM NUMBER], [NUMBER OF ROWS TO RETURN])

1 голос
/ 30 ноября 2009

Самый простой (и, может быть, лучший / самый безопасный?) Способ сделать это - добавить эти строки в таблицу столько раз, сколько вы хотите, чтобы вес был - скажем, я хочу, чтобы «дерево» встречалось в 2 раза чаще, чем « Собака "- я вставляю ее 2 раза в таблицу и вставляю" Собаку "один раз и просто выбираю элементы случайным образом один за другим.

Если строки сложные / большие, то было бы лучше создать отдельную таблицу (weighted_Elements или что-то в этом роде), в которой у вас будут только внешние ключи для реальных строк, вставленные столько раз, сколько диктуют веса.

0 голосов
/ 06 ноября 2017

Проблема называется отбором проб резервуаров (https://en.wikipedia.org/wiki/Reservoir_sampling)

Алгоритм A-Res легко реализовать в SQL:

SELECT *
FROM table
ORDER BY pow(rand(), 1 / weight) DESC
LIMIT 10;
0 голосов
/ 08 декабря 2012

Я пришла искать ответ на тот же вопрос - я решила придумать это:

id      weight
1       5
2       1

SELECT * FROM table ORDER BY RAND()/weight

это не точно, но использует случайное, поэтому я не могу ожидать точного. Я пробежал 70 раз, чтобы получить номер 2 10 раз. Я бы ожидал 1/6, но получил 1/7. Я бы сказал, что это довольно близко. Мне пришлось бы запустить сценарий, чтобы сделать это несколько тысяч раз, чтобы получить действительно хорошую идею, если он работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...