算法/确定加权奖励的查询

问题描述 投票:0回答:1

我正在开发一个游戏,在该游戏中,将为用户提供随机奖励,并通过“分享”系统对每种奖励的传递机会进行加权。为了说明这个问题,让我们看一个例子:

比方说,我将给出纯粹的随机奖励,而不是[A,B,C]。这就像获取随机索引并从数组中返回任何奖励一样简单。

但是,在我的用例中,奖励集是具有“份额”系统的权重。因此,我们的情况如下:

  • A-权重为2。
  • B-3的权重。
  • C-权重为5。

所以集合看起来像这样:[A,A,B,B,B,C,C,C,C,C]。

现在,我可以只是构建该数组并获得类似的随机结果,但是我担心性能的影响。这些奖励存储在数据库中(如果考虑到这一点,则使用Django和PSQL作为后端),并且可能有100多个潜在奖励,每个奖励的权重为1-100(或更高)。

因此,我试图找出一种有效的方法来根据这种权重获得随机奖励。


在写这篇文章的时候,我想到了一件事(但我想听听其他想法):

  • 更新奖励集后,构建一次阵列,然后为每个奖励分配一定百分比的机会。因此,一次计算百分比。
  • 在上面,我们将得到类似:[A:0.2,B:0.3,C:0.5]。
  • 然后,我们可以得到0到1之间的随机数,并获得最接近的奖励而无需结束? (因此,0.4的随机掷骰将获得B,因为0.3最接近0.45而不高于0.45)。
    • 但是,我一直在努力思考如何为此编写高效的查询。也许查询百分比低于滚动百分比的所有奖励(在上面的示例中为0.45),然后从这些结果中返回百分比最高的奖励。

我想我可能已经回答了我自己的问题,但是希望从第三方的角度来看。谢谢大家!

python django postgresql algorithm random
1个回答
0
投票

您应该使用累计百分比。设置示例:

create table weights(label text, weight int, cumulative_percentage float);
insert into weights (label, weight) values
('A', 2),
('B', 3),
('C', 5);

update weights w
set cumulative_percentage = cumulative_sum::float/ total
from (
    select 
        label,
        sum(weight) over (order by label) as cumulative_sum,
        sum(weight) over () as total
    from weights
    ) s
where s.label = w.label;

所以表看起来像这样:

select *
from weights

 label | weight | cumulative_percentage 
-------+--------+-----------------------
 A     |      2 |                   0.2
 B     |      3 |                   0.5
 C     |      5 |                     1
(3 rows)

使用公共表表达式在循环中获得单个随机数:

with seed(r) as (select random())
select min(label)
from weights, seed
where r <= cumulative_percentage

或创建函数:

create or replace function get_percentageed_reward(r float)
returns text language sql as $$
    select min(label)
    from weights
    where r <= cumulative_percentage
$$; 

检查算法的结果:

select get_percentageed_reward(random()), count(*)
from generate_series(1, 100000)
group by 1
order by 1

 get_percentageed_reward | count 
-------------------------+-------
 A                       | 20008
 B                       | 30165
 C                       | 49827
(3 rows)    
© www.soinside.com 2019 - 2024. All rights reserved.