SQL中值小于给定日期,月份的值

时间:2017-10-24 18:06:51

标签: python sql postgresql sqlalchemy

我正在尝试使用python中的SQLAlchemy计算中值作为时间的函数。我要找的是在给定日期以下的所有时间的中位数。

所以一些示例数据是

Date       Value  
2017-08-02 0.11   
2017-08-22 0.34   
2017-08-24 0.66   
2017-09-05 1.23   
2017-09-26 0.15   
2017-10-07 0.99   
2017-10-13 1.01   
2017-10-22 0.44   
2017-10-28 0.89

我想要计算的是8月份所有值的中位数,然后是8月份 9月份所有值的中位数,然后是8月份所有值的中位数九月十月。

示例输出将是这样的。

Date       Median
2017-08-01 0.34  
2017-09-01 0.34  
2017-10-01 0.66  

在实际数据中有更多的值,因此中位数实际上是有意义的。我事先并不知道每月会有多少参赛作品。

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

我相当确定存在更好的方法,但您可以从数据中选择月份 - 由此处组中的最大日期表示 - 然后分别计算每个月及以下的第50个百分点:

months = select([func.max(tbl.c.date).label('date')]).\
    group_by(func.date_trunc('month', tbl.c.date)).\
    alias('months')

percentiles = select([
        func.percentile_cont(0.5).
            within_group(tbl.c.value).
            label('median')]).\
    where(tbl.c.date <= months.c.date).\
    lateral('percentiles')

query = select([months.c.date,\
                percentiles.c.median]).\
    order_by(months.c.date)

结果是:

In [8]: engine.execute(query).fetchall()
2017-10-25 16:44:18,637 INFO sqlalchemy.engine.base.Engine SELECT months.date, percentiles.median 
FROM (SELECT max(foo.date) AS date 
FROM foo GROUP BY date_trunc(%(date_trunc_1)s, foo.date)) AS months, LATERAL (SELECT percentile_cont(%(percentile_cont_1)s) WITHIN GROUP (ORDER BY foo.value) AS median 
FROM foo 
WHERE foo.date <= months.date) AS percentiles ORDER BY months.date
2017-10-25 16:44:18,637 INFO sqlalchemy.engine.base.Engine {'percentile_cont_1': 0.5, 'date_trunc_1': 'month'}
Out[8]: 
[(datetime.date(2017, 8, 24), 0.34),
 (datetime.date(2017, 9, 26), 0.34),
 (datetime.date(2017, 10, 28), 0.66)]

如果需要,截止日期到月的第一天应该是非常简单的。请注意,您也可以使用标量子查询代替LATERAL。