数据库中有几百本书记录,每条记录都有一个发布时间。在网站的主页上,我需要编写一些代码来随机挑选10本书并将它们放在那里。要求是新书需要有更高的展示机会。
由于时间是整数,我这样想是为了计算每本书的概率:
Probability of a book to be drawn = (current time - publish time of the book) / ((current time - publish time of the book1) + (current time - publish time of the book1) + ... (current time - publish time of the bookn))
在绘制一本书之后,下一轮循环将从分母中减去(当前时间 - 书的发布时间)并重新计算每本剩余书籍的概率,循环一直持续到10本书已经绘制。
这个算法是否正确?
顺便说一句,该网站是用PHP编写的。
如果您有更好的算法,请随意提出一些PHP代码。
非常感谢大家。
答案 0 :(得分:1)
首先,我认为你的公式将保证早期的书籍被选中。尝试根据以下内容设置初始概率:
年龄 - 自出版以来的日子
最大(年龄) - 样本中最早的书
书籍时代(i) - 书的年龄我
... Prob(i)= [Max(age)+ e - Book Age(i)] /所有i的总和[Max(age)+ e - Book age(i)]
值e确保最旧的书籍有被选中的概率。既然已经完成了,您可以随时重新计算任何样本的概率。
现在你必须找到一种采用UNBIASED方式挑选书籍。可能最好的方法是使用上面的方法计算累积分布,然后选择一个均匀的(0,1)r.v.找到那个r.v.在累积分布中并选择离它最近的书。
无法帮助您进行编码。合理?
答案 1 :(得分:1)
这是一个非常相似的问题可能会有所帮助:Random weighted choice解决方案是在C#中,但代码非常易读且接近PHP语法,因此应该很容易适应。
例如,以下是在MySQL中如何做到这一点:
首先计算所有书籍的总年龄并将其存储在MySQL用户变量中:
SELECT SUM(TO_DAYS(CURDATE())-TO_DAYS(publish_date)) FROM books INTO @total;
然后随机选择书籍,按年龄加权:
SELECT book_id FROM (
SELECT book_id, TO_DAYS(CURDATE())-TO_DAYS(publish_date) AS age FROM books
) b
WHERE book_id NOT IN (...list of book_ids chosen so far...)
AND RAND()*@total < b.age AND (@total:=@total-b.age)
ORDER BY b.publish_date DESC
LIMIT 10;
请注意,@total
只有在书籍通过随机选择测试时才会减少,因为AND
表达式会短路。
不保证一次性选择10本书 - 甚至不保证在给定的通行证上选择任何书籍。所以你必须重新开始第二步,直到找到10本书。 @total
变量保留其减少的值,因此您无需重新计算它。