在Ruby/Rails中从数组中加权随机选择

3

我有一个Rails模型,想从中随机选择一条记录。我通过一个类似以下的命名作用域来实现:

named_scope :random,  lambda { { :order=>'RAND()', :limit => 1  } }

现在我已经在表示每行应该被选择的概率的模型中添加了一个整数字段“weight”。

那么现在我该如何进行加权随机选择呢?

我在snippets.dzone.com上找到并尝试了两种方法,它们扩展了Array类并添加了加权随机函数,但是都没有为我工作或选择随机项。

我正在使用REE 1.8.7和Rails 2.3。


1
可能最好加上你正在使用的数据库。在 Ruby 中做起来并不难,但在数据库中进行操作可能更有效率。 - Jakub Hampl
哦,是的,忘了提到我在使用mysql。但是我太专注于用ruby解决它了,甚至没有考虑在查询层面上解决它。 - capsized
2个回答

5
也许我完全理解错误了,但是您是否可以将“权重”列作为随机数的因素来使用?(根据数据库,可能需要采取一些预防措施,以防止产品溢出。)
named_scope :random,  lambda { { :order=>'RAND()*weight', :limit => 1  } }

你对于权重是影响随机数的因素是正确的。这比我最初想象的要简单得多!谢谢! - capsized
3
期望的结果得不到实现。假设有一张表格,有999条记录,所有的重量都是1,除了一条记录的重量是2。你本来期望特殊记录被选中的概率是1/500(因为它的重量是2,总重量是1000),但实际上它被选中的次数是一半(每当其rand()函数的值大于1时)。此外,即使只需要一条记录,它也要执行1000次rand()函数。你最好使用一个查询获得总数,在ruby中选择重量区间内的一个点,然后根据该数字选择一条记录。 - rewritten

0

在一个查询中,您应该:

  • 计算总重量
  • 将其乘以一个随机因子,得到一个重量阈值
  • 再次扫描表格,累加直到达到重量阈值。

在SQL中,它可能是这样的(未真正尝试)

SELECT SUM(weight) FROM table INTO @totalwt;
@lim := FLOOR(RAND() * @totalwt);
SELECT id, weight, @total := @total + weight AS cumulativeWeight
     FROM table WHERE cumulativeWeight < @lim, (SELECT @total:=0) AS t;

受到在MySQL中获取累积和的最佳查询的启发。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接