python - 计算和存储每日、每周、每月和每年的平均数据

标签 python django

我昨天在 SO 上问了一个题为 Deciding and implementing a trending algorithm in Django 的问题.很多人提出了一个简单的东西,比如平均值(指数、加权等) 我有一个名为 Book 的模型和另一个名为 Readers 的模型:

class Book(models.Model):
    name = models.charField()

class Reader(models.Model):
    date = models.DateField()
    book = models.ForeignKey(Book)
    reader_count = models.PostiveIntegerField()

结构简单。每天都会增加新书,每天都会增加每本书的读者数量。即一本书每天会有一个读者计数,多条记录。

我需要计算本周、当月和当年书籍的平均值。除了当前数据,我还想保留历史数据。

如果我尝试从数据库中查询此类数据,那将是一个巨大的打击。不会吧。此外,我正在尝试使用简单的平均数来实现这个系统,但后来,我希望能够灵活地改变我的计算方法。我有两个选择 -

  • 一个,每次添加新的 Reader 记录时,我都可以部分更新存储计算数据的另一个表中的数据。

  • 两个,我可以在其中通过当前日/周/月的脚本每晚重建聚合数据。

这是一些示例数据和结果。

Book  Date        Count
----  ----------  -----
AAAA  01.01.2012    10
AAAA  02.01.2012    20
AAAA  03.01.2012    30
AAAA  04.01.2012    30
AAAA  05.01.2012    40
AAAA  06.01.2012    10
AAAA  07.01.2012    25
AAAA  08.01.2012    15
AAAA  09.01.2012    10

第 1 周的平均读者数是:23.5。 第 2 周(本例为本周)的平均读者数为:12.5 ..对于当前的月份和年份将是 21.1

HTH.

为了尝试其中的任何一个,我想构建一个系统来存储数据。我需要每天、每周和每月存储平均值。但是我很迷茫我应该实现什么样的表结构?如果可能的话,我不想重新发明轮子,所以如果你们中有人知道任何允许我完成此任务的软件包,那就太好了。

谢谢。

最佳答案

Postgres 非常擅长与您的其他流量同时进行此类计算,所以不要太担心负载(只要您在请求-响应周期之外运行这种批处理作业) .

您可能考虑做的一件事是将此类工作拆分为可缓存的小单元。即每个月的平均数实际上是过去 4 周的平均数,每年的每个平均数是过去 12 个月的平均数,而且这一切都只是在每本书的基础上完成的,所以为什么不做小的子集请求中的工作。

from django.core.cache import cache
from datetime import timedelta

def cached(key, expire)
    def wrapped(f):
        def func(*args, **kwargs):
            result = cache.get(key%args%kwargs)
            if result is None:
                result = f(*args, **kwargs)
                cache.set(key%args%kwargs, result, expire)
            return result
        return func
    return wrapped

@cached("book:%s:avg:week:%s", 3600*24) #cache for a day, rolling results!
def book_read_week_average(book_id, week_start):
    week_end = week_start + timedelta(days=7)
    return Reader.objects.filter(book_id=book_id, date_gte=week_start, date_lt=week_end) \
                         .aggregate(Avg('count'))['count_avg']

@cached("book:%s:avg:month:%s", 3600*24) #cache for a day for rolling results
def book_read_month_average(book_id, month_start):
    month_end = month_start + timedelta(days=31)
    return Reader.objects.filter(book_id=book_id, date_gte=month_start, date_lt=month_end) \
                         .aggregate(Avg('count'))['count_avg']

@cached("author:%s:avg:month:%s", 3600*24)
def author_read_month_average(author_id, month_start):
    return sum(book_read_month_average( book.id )
               for book in Book.objects.filter(author_id=author_id) )

使用函数组合和缓存函数,您只生成需要的数据,并且只在需要时生成。您还可以将此信息存储在 redis 而不是 django 缓存中,并利用读取计数的原子增量,允许实时读取统计信息。

关于python - 计算和存储每日、每周、每月和每年的平均数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9300922/

相关文章:

javascript - 如何通过 Selenium Python 根据 HTML 单击复选框

Python - 这是初始化空集矩阵的正确方法吗?

python - Django INSTALLED_APPS 中的点路径无法导入

python - 将信息从字符串转换为字典

python - 通用详细 View UserProfileDetailView 必须使用对象 pk 或 URLconf 中的 slug 调用

Django - fixture 中的外键

django - Django 模型类始终排除 "unpublished"实例的一般规则

python - 在 Django 管理中,包括 auth.User 作为内联

python - 使用 MySQL 时,Django IntegerField 将 0 作为 None 值检索

python - Django RSS feed 按类别