mysql 基于概率机会选择随机值

fdbelqdn  于 2023-05-28  发布在  Mysql
关注(0)|答案(2)|浏览(158)

如何根据分配给每一行的概率机会从数据库中随机选择一行。

  • 示例:*
Make        Chance  Value
ALFA ROMEO  0.0024  20000
AUDI        0.0338  35000
BMW         0.0376  40000
CHEVROLET   0.0087  15000
CITROEN     0.016   15000
........

我如何选择随机生成名称和它的值的基础上,它必须被选中的概率。
rand()ORDER BY的组合是否有效?如果是这样,最好的方法是什么?

mwyxok5s

mwyxok5s1#

我有同样的需求,并试图为SQL服务器编写一个查询。我的答案是基于@gordon-linoff的使用概率累积和的查询。

with rand AS (SELECT id, random=RAND() FROM Tiers)
   , cumsum AS (SELECT id, cum_sum=SUM(probability) Over (Order By id) from Tiers)
Select TOP 1 t.id,
             t.name,
             t.probability
FROM Tiers t
         inner join rand r on t.id = r.id
         inner join cumsum c on t.id = c.id
WHERE c.cum_sum - r.random >= 0
ORDER BY c.cum_sum - r.random ASC

我已经写了一个完整的摘要来测试https://github.com/AlahmadiQ8/cumulative-probability-sql
这里是累积和概率的直观解释
| 项目|机率|累积的|
| - -----|- -----|- -----|
| 一个|0.2| 0.2|
| B| 0.3| 0.5|
| C类|0.5|一个|
如果是随机数x = 0.45,那么我们应该返回B,因为x0.2 < x <= 0.5

x
|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|
           0.2               0.5                            1
└──────────┘ └───────────────┘ └───────────────────────────┘
      A              B                        C
gxwragnw

gxwragnw2#

您可以通过使用rand()然后使用累积和来实现这一点。假设它们加起来是100%:

select t.*
from (select t.*, (@cumep := @cumep + chance) as cumep
      from t cross join
           (select @cumep := 0, @r := rand()) params
     ) t
where @r between cumep - chance and cumep
limit 1;

注意事项:

  • rand()在子查询中调用一次以初始化变量。不希望多次调用rand()
  • 随机数恰好在两个值之间的边界上的可能性很小。limit 1任意选择1。
  • 如果在cumep > @r时停止子查询,则可以提高效率。
  • 这些值不必按任何特定顺序。
  • 这可以修改为处理总和不等于1的机会,但这将是另一个问题。

相关问题