明显(但价格昂贵)的解决方案:
我想在这样的表中存储音轨(1-10)的等级:
TrackID
Vote
然后一个简单的
SELECT AVERAGE(Vote) FROM `table` where `TrackID` = some_val
计算平均值。
但是,我担心这方面的可扩展性,特别是因为每次都需要重新计算。
建议,但可能是愚蠢的解决方案:
TrackID
Rating
NumberOfVotes
每次有人投票时,Rating
都会更新
new_rating = ((old_rating * NumberOfVotes) + vote) / (NumberOfVotes + 1)
并存储为TrackID
的新Rating
值。现在每当需要Rating
时,它都是简单的查找,而不是计算。
显然,这并不计算平均值。我尝试了一些小数据集,它近似于均值。我相信它会随着数据集的增加而收敛?但我担心它可能会分歧!
你们觉得怎么样?谢谢!
答案 0 :(得分:8)
假设您具有无限的数字精度,该计算会正确更新均值。在实践中,您可能正在使用整数类型,因此它并不准确。
如何存储累积投票数和投票数? (即total=total+vote
,numVotes=numVotes+1
)。这样,您可以通过将一个除以另一个来获得精确的平均值。
如果您获得的票数超出您所使用的数据类型的范围,则此方法只会中断。所以使用一个大数据类型(32位应该足够了,除非你期待约40亿票)!
答案 1 :(得分:3)
在您的表格中存储TrackId
,RatingSum
,NumberOfVotes
。
每次有人投票,
然后选择
SELECT TrackId, RatingsSum / NumberOfVotes FROM ...
答案 2 :(得分:2)
您的解决方案完全合法。并且差值仅为从完整源集计算的值的浮点精度的几倍。
答案 3 :(得分:2)
你可以在不掌握所有要点的情况下计算出运行平均值和标准偏差。您只需要累积总和,平方和和点数。
这不是近似值;平均值和标准差是准确的。
这是一个演示的Java类。您可以根据需要调整SQL解决方案:
package statistics;
public class StatsUtils
{
private double sum;
private double sumOfSquares;
private long numPoints;
public StatsUtils()
{
this.init();
}
private void init()
{
this.sum = 0.0;
this.sumOfSquares = 0.0;
this.numPoints = 0L;
}
public void addValue(double value)
{
// Check for overflow in either number of points or sum of squares; reset if overflow is detected
if ((this.numPoints == Long.MAX_VALUE) || (this.sumOfSquares > (Double.MAX_VALUE-value*value)))
{
this.init();
}
this.sum += value;
this.sumOfSquares += value*value;
++this.numPoints;
}
public double getMean()
{
double mean = 0.0;
if (this.numPoints > 0)
{
mean = this.sum/this.numPoints;
}
return mean;
}
public double getStandardDeviation()
{
double standardDeviation = 0.0;
if (this.numPoints > 1)
{
standardDeviation = Math.sqrt((this.sumOfSquares - this.sum*this.sum/this.numPoints)/(this.numPoints-1L));
}
return standardDeviation;
}
public long getNumPoints() { return this.numPoints; }
}
答案 4 :(得分:1)
您的解决方案的小改进。你有桌子:
TrackID
SumOfVotes
NumberOfVotes
当有人投票时,
NumberOfVotes = NumberOfVotes + 1
SumOfVotes = SumOfVotes + ThisVote
并且看到平均值,然后才进行划分:
SELECT TrackID, (SumOfVotes/NumberOfVotes) AS Rating FROM `table`
我想补充一点,原始(明显且昂贵)的解决方案与计算平均值时提供的解决方案相比只是昂贵的。 添加,删除或更改投票时更便宜。 我想原来的表
TrackID
Vote
VoterID
仍然需要在提供的解决方案中使用来跟踪每个选民的投票(评级)。因此,必须为此表中的每个更改(插入,删除或投票更新)更新两个表。
换句话说,原始解决方案可能是最好的方法。