【问题标题】:Select random row from MySQL (with probability)从 MySQL 中选择随机行(有概率)
【发布时间】:2023-04-03 09:47:01
【问题描述】:

我有一个 MySQL 表,其中有一个名为 cur_odds 的行,它是一个百分比数字,表示该行将被选中的百分比概率。例如,当您运行 100 个查询时,如何进行查询以大约以该频率实际选择行?

我尝试了以下方法,但概率为 0.35 的行最终在大约 60-70% 的时间内被选中。

SELECT * FROM table ORDER BY RAND()*cur_odds DESC

表中所有cur_odds的值加起来正好是1。

【问题讨论】:

  • ORDER BY RAND() 对于大型数据集可能非常慢,因为它是 O(n log(n))。您的表格将有多少行?

标签: mysql probability


【解决方案1】:

如果cur_odds 很少更改,您可以实现以下算法:

1) 创建另一列prob_sum,用于该列

prob_sum[0] := cur_odds[0]

对于 1

prob_sum[i] := prob_sum[i - 1] + cur_odds[i]

2) 生成一个从0到1的随机数:

rnd := rand(0,1)

3) 找到prob_sum > rnd 所在的第一行(如果您在prob_sum 上创建BTREE 索引,查询应该会更快):

创建索引 prob_sum_ind ON

(prob_sum);

SET @rnd := RAND();

SELECT MIN(prob_sum) FROM

WHERE prob_sum > @rnd;

【讨论】:

    【解决方案2】:

    鉴于您的上述 SQL 语句,您在 cur_odds 中的任何数字都不是选择每一行的概率,而是只是一个任意权重(相对于所有的“权重”其他行),最好将其解释为向排序表顶部浮动的相对趋势。每行中的实际值是没有意义的(例如,您可以有 4 行的值分别为 0.35、0.5、0.75 和 0.99,或者您可以有 35、50、75 和 99 的值,结果将是相同的)。

    更新:以下是您的查询发生的情况。您有一行 cur_odds 值为 0.35。为了便于说明,我将假设其他 9 行都具有相同的值 (0.072)。同样为了说明起见,我们假设 RAND() 返回一个从 0.0 到 1.0 的值(实际上可能)。

    每次运行此 SELECT 语句时,都会通过将其 cur_odds 值乘以从 0.0 到 1.0 的 RAND() 值来为每一行分配一个排序值。这意味着具有 0.35 的行将具有介于 0.0 和 0.35 之间的排序值。

    每隔一行(值为 0.072)将具有介于 0.0 和 0.072 之间的排序值。这意味着您的某一行的排序值大于 0.072 的可能性约为 80%,这意味着不可能任何其他行的排序更高。这就是为什么您的 cur_odds 值为 0.35 的行比您预期的更频繁地首先出现。

    我错误地将cur_odds 值描述为相对变化权重。它实际上起到最大相对权重的作用,然后会涉及一些复杂的数学来确定所涉及的实际相对概率。

    我不确定你需要什么可以用直接的 T-SQL 来完成。我已经多次实现了加权概率选择器(具有讽刺意味的是,今天早上我什至要问一个关于最佳方法的问题)但总是在代码中。

    【讨论】:

    • 其实我有10行,cur_odds中的10个值正好等于1。
    • 尝试将所有值乘以 10(这样它们的总和正好为 10.0),您会看到得到相同的排序结果。或者你可以将它们全部除以 3,或者乘以 100 等等。
    猜你喜欢
    • 2011-10-20
    • 2019-05-10
    • 1970-01-01
    • 2012-10-13
    • 2021-04-27
    • 2013-03-11
    • 1970-01-01
    • 1970-01-01
    • 2013-06-19
    相关资源
    最近更新 更多