在Django中决定和实现趋势算法

17 投票
4 回答
6259 浏览
提问于 2025-04-17 13:02

我有一个Django应用程序,需要实现一个简单的热门书籍排名算法。作为一个新手,我感到很迷茫:

我有两个模型,Book(书籍)和Reader(读者)。每晚,我的数据库会添加新书籍。同时,每本书的读者数量也会每天更新,也就是说,每本书会有多个读者统计记录(每天一条记录)。

在一段时间内(比如过去一周、一个月或一年),我想列出最受欢迎的书籍,我应该使用什么算法呢?

书籍的受欢迎程度不需要实时更新,因为每本书的读者数量是每天更新的。

我找到了一篇文章,里面提到了一种计算热门维基百科文章的方法,但那篇文章只展示了如何计算当前的趋势。

正如有人在StackOverflow上指出的,这其实是一个非常简单的基础趋势算法,只是计算两个数据点之间的斜率,所以我猜这只是显示了昨天和今天之间的趋势。

我并不想要像Hacker News、Reddit等网站那样复杂的趋势算法。

我只有两个数据轴,读者数量和日期。

有没有什么想法,我该如何实现呢?对于一个从未接触过统计或算法的人来说,这似乎是一个非常艰巨的任务。

提前感谢大家的帮助。

4 个回答

0

你可以把StackOverflow的声望排名作为一个例子。

用户可以选择不同的查看方式:按月、按年等等。

在你的情况下:你可以查看每本书按月、按年的阅读人数。

为了实现这个功能,你需要每天记录每本书的读者数量。

reader( date, book, total )

然后就简单多了:

   Book.objects.filter(  
                   boor__reader__date__gte = some_date
                      ).annotate(
                            num_readers=Sum('book__reader__total')
                                ).order_by('-num_readers')
0

受欢迎程度很简单;你只需要统计一下读者的数量,然后按这个数量排序:

Book.objects.annotate(reader_count=Count('readers')).order_by('-reader_count')

而“趋势”就比较复杂了,因为它关注的是受欢迎程度的变化,也就是说,最近哪些书的读者增加得最多。如果你想要这样的功能,就需要在后台运行一些东西,来记录每天的读者数量。

9

我能想到的最简单的趋势“算法”就是n天移动平均值。我不太确定你的数据是怎么结构的,但假设你有这样的数据:

books = {'Twilight': [500, 555, 580, 577, 523, 533, 556, 593],
         'Harry Potter': [650, 647, 653, 642, 633, 621, 625, 613],
         'Structure and Interpretation of Computer Programs': [1, 4, 15, 12, 7, 3, 8, 19]
        }

简单的移动平均就是把最近的n个值加起来,然后算个平均:

def moving_av(l, n):
    """Take a list, l, and return the average of its last n elements.
    """
    observations = len(l[-n:])
    return sum(l[-n:]) / float(observations)

这里的切片表示法就是从列表的末尾开始,抓取倒数第n个到最后一个的值。移动平均是一种常用的方法,可以把单个的高峰或低谷带来的噪音平滑掉。这个函数可以这样使用:

book_scores = {}
for book, reader_list in books.iteritems():
    book_scores[book] = moving_av(reader_list, 5)

你可以试着调整一下你想要计算的天数。如果你想更关注最近的趋势,可以考虑使用一种叫做加权移动平均的方法。

如果你想关注的是阅读量的增长,而不是绝对的阅读量,可以计算一下30天移动平均和5天移动平均的百分比变化:

d5_moving_av = moving_av(reader_list, 5)
d30_moving_av = moving_av(reader_list, 30)
book_score = (d5_moving_av - d30_moving_av) / d30_moving_av

通过这些简单的工具,你可以灵活地调整你想强调的过去趋势的程度,以及你想要平滑(或者不平滑)高峰的程度。

撰写回答