根据项目的年龄以及项目收到的投票,点击次数或购买次数,有大量suggested algorithms用于计算受欢迎程度。但是,我看到的更健壮的方法通常需要过于复杂的计算和多个存储的值,这会使数据库变得混乱。我一直在考虑一种非常简单的算法,它不需要存储任何变量(除了流行度值本身)并且只需要一个简单计算。这太荒谬了:
p = (p + t) / 2
此处, p是存储在数据库中的受欢迎度值, t是当前时间戳。首次创建项目时,必须初始化 p 。有两种可能的初始化方法:
请注意,初始化方法(1)为最近添加的项目提供了优于历史项目的明显优势,从而添加了相关性元素。另一方面,初始化方法(2)在与历史项目进行比较时将新项目视为等于。
假设您使用初始化方法(1)并使用当前时间戳初始化 p 。当项目收到第一次投票时, p 成为创建时间和投票时间的平均值。因此,流行度值 p 仍然表示有效的时间戳(假设您舍入到最接近的整数),但它表示的实际时间是抽象的。
使用此方法,只需要一个简单的计算,并且只需要在数据库中存储一个值( p )。此方法还可以防止失控值,因为给定项目的受欢迎程度永远不会超过当前时间。
在1天内工作的算法示例:http://jsfiddle.net/q2UCn/
该算法在1年期间工作的示例:http://jsfiddle.net/tWU9y/
如果您希望投票以亚秒级间隔稳定地流入,那么您将需要使用微秒时间戳,例如PHP microtime()
函数。否则,标准UNIX时间戳将起作用,例如PHP time()
函数。
现在我的问题是:你认为这种方法有什么重大缺陷吗?
答案 0 :(得分:9)
我认为这是一种非常好的方法,因为它很简单。一个非常有趣的结果。
我做了一个快速的计算,发现这个算法似乎确实理解了“流行度”的含义。它的问题在于它明显倾向于支持这样的近期投票:
想象一下,我们花时间把它分成100到1000之间的离散时间戳值。假设在t = 100时,A和B(两个项目)都有相同的P = 100.
A gets voted 7 times on 200, 300, 400, 500, 600, 700 and 800
resulting on a final Pa(800) = 700 (aprox).
B gets voted 4 times on 300, 500, 700 and 900
resulting on a final Pb(900) = 712 (aprox).
当t = 1000时,A和B都会收到投票,所以:
Pa(1000) = 850 with 8 votes
Pb(1000) = 856 with 5 votes
为什么呢?因为该算法允许项目快速击败历史领导者,如果它收到更多近期投票(即使该项目的总票数较少)。
编辑包括模拟
OP创造了一个很好的小提琴,我改变了以获得以下结果:
Item A receives one vote each day from 1970 till 2012 (15339 votes)
Item B receives one vote each month from Jan to Jul 2012 (7 votes)
The result: B is more popular than A.
答案 1 :(得分:3)
我看到一个问题,只有最后的~24票数。
p_i+1 = (p + t) / 2
我们有两票
p2 = (p1 + t2) / 2 = ((p0 + t1) /2 + t2 ) / 2 = p0/4 + t1/4 + t2/2
扩大32票的范围给出:
p32 = t*2^-32 + t0*2^-32 + t1*2^-31 + t2*2^-30 + ... + t31*2^-1
因此,对于带符号的32位值,t0对结果没有影响。因为t0除以2 ^ 32,所以它对p32没有贡献。
如果我们有两个项目A和B(无论差异有多大),如果他们都获得相同的32票,他们将具有相同的受欢迎程度。所以你的历史可以追溯到32票。如果最后32票相同,则2032和32票没有区别。
如果差异小于一天,则在17票之后它们将相等。
答案 2 :(得分:2)
提出的算法是一种很好的方法,并且是Exponential Moving Average的特殊情况,其中alpha = 0.5:
<div class="test-sticker">
<div class="wrapper">
<div class="sticker">
<div class="reveal circle_wrapper">
<div class="circle"></div>
</div>
<div class="sticky">
<div class="front circle_wrapper">
<div class="circle"></div>
</div>
</div>
<div class="sticky anim750">
<div class="back circle_wrapper anim750">
<div class="circle anim750"></div>
</div>
</div>
</div>
</div>
</div>
调整以下事实的一种方法:建议的alpha = 0.5解决方案倾向于偏爱最近的投票(如daniloquio所指出的)是为alpha选择较高的值(例如0.9或0.99)。请注意,将其应用于daniloquio提出的测试用例不起作用,但是,因为当alpha增加时,算法需要更多的“时间”来解决(因此数组应该更长,这在实际应用中通常是正确的) )。
因此:
答案 3 :(得分:1)
缺点是100票的东西通常比最近只有一票的东西更有意义。但是,如果你的方案的变体能够合理地运行起来,那就不难了。
答案 4 :(得分:0)
我不认为上面讨论的逻辑会起作用。 p_i + 1 =(p_i + t)/ 2
在时间戳上查看文章A:70,80,90受欢迎程度(文章A):82.5
B条按时间戳查看:50,60,70,80,90受欢迎程度(文章B):80.625
在这种情况下,B条的受欢迎程度应该更高。首先,B条最近被视为A条,其次,它也被视为比A条更多次。