【问题标题】:Creating cumulative moving average on SQLite在 SQLite 上创建累积移动平均线
【发布时间】:2020-01-06 13:23:04
【问题描述】:

我正在尝试在 SQLite 中创建累积移动平均线。

作为复习,在累积移动平均线 (CMA) 中,数据以有序数据流的形式到达,我想获得直到当前数据点的所有数据的平均值。

我的表看起来像:

Continent,Date,Measure,Value
Antarctica,03/01/2019 12:00:00 AM,Passengers,346158
South America,03/01/2019 12:00:00 AM,Ships,6483
South America,03/01/2019 12:00:00 AM,Flights,19
Antarctica,02/01/2019 12:00:00 AM,Passengers,172163
South America,02/01/2019 12:00:00 AM,Cargo Ships,1319
Antarctica,01/01/2019 12:00:00 AM,Passengers,56810

以前的解决方案(例如 1 或 2)描述了每月或每周的移动平均线。不过,虽然我可以逐月保持这个平均值,但我正在尝试建立一个累积平均值。

我试过这样做:

SELECT T1.Date, AVG(T2.VALUE) from my_table AS T1 INNER JOIN my_table AS T2 ON datetime(T1.Date, '-1 Month') <= datetime(T2.Date) 
  AND datetime(T1.Date, '+1 Month') >= datetime(T2.Date) GROUP BY
  T1.date;

但是当我使用sqlite时,日期时间操作会产生错误:sqlite does not have operation datetime.

我什至尝试了简单的命令:SELECT AVG(VALUE) FROM my_table GROUP BY MEASURE, DATE, CONTINENT,但是按移动平均线分组,这并没有解决我的问题。

我想要做什么:

Continent,Date,Measure,Value,Average
Antarctica,03/01/2019 12:00:00 AM,Passengers,346158,114487
South America,03/01/2019 12:00:00 AM,Ships,6483,0
South America,03/01/2019 12:00:00 AM,Flights,19,0
Antarctica,02/01/2019 12:00:00 AM,Passengers,172163,56810
South America,02/01/2019 12:00:00 AM,Cargo Ships,1319,0
Antarctica,01/01/2019 12:00:00 AM,Passengers,56810,0

Average 列是过去几个月到大陆的总过境次数和过境方式的月平均值。因此,要计算第一条线路的平均值(即,在 3 月之前的所有月份中穿越南极洲的乘客总数的月平均值),您将采用 February 156,891 + 15,272 = 172,163 和 @ 中穿越南极洲的乘客总数的平均总和987654331@,并将其四舍五入到最接近的整数round(228,973/2) = 114,487。

有没有更简单的方法来解决这个问题?

【问题讨论】:

  • 您的样本数据中的156,891 和15,272 在哪里?

标签: sql sqlite datetime moving-average


【解决方案1】:

首先,修复您的时间戳,使其采用可排序的格式,例如 sqlite date and time functions 支持的 ISO-8601 格式。而不是03/01/2019 12:00:00 AM,请使用2019-03-01 00:00:00(或者如果您不关心时间,只需使用2019-03-01,只需使用日期即可)。这会使您的 CSV 数据看起来像:

Continent,Date,Measure,Value
Antarctica,2019-03-01 00:00:00,Passengers,346158
South America,2019-03-01 00:00:00,Ships,6483
South America,2019-03-01 00:00:00,Flights,19
Antarctica,2019-02-01 00:00:00,Passengers,172163
South America,2019-02-01 00:00:00,Cargo Ships,1319
Antarctica,2019-01-01 00:00:00,Passengers,56810

然后可以使用窗口函数(Sqlite 3.25中引入)轻松计算前几个月的累积平均值:

SELECT continent, date, measure, value,
       cast(round(ifnull(avg(value)
                          OVER (PARTITION BY continent, measure
                                ORDER BY date
                                ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),
                         0),
                  0) AS INTEGER) AS Average
FROM crossings
ORDER BY date DESC, continent, measure DESC;

给了

Continent   Date                 Measure     Value       Average   
----------  -------------------  ----------  ----------  ----------
Antarctica  2019-03-01 00:00:00  Passengers  346158      114487 
South Amer  2019-03-01 00:00:00  Ships       6483        0    
South Amer  2019-03-01 00:00:00  Flights     19          0   
Antarctica  2019-02-01 00:00:00  Passengers  172163      56810   
South Amer  2019-02-01 00:00:00  Cargo Ship  1319        0     
Antarctica  2019-01-01 00:00:00  Passengers  56810       0     

如果卡在不支持窗口函数的旧版本上,您可以使用相关子查询来计算累积平均值:

SELECT continent, date, measure, value,
       ifnull((SELECT cast(round(avg(c2.value), 0) AS INTEGER)
               FROM crossings AS c2
               WHERE c2.continent = c.continent
                 AND c2.measure = c.measure
                 AND c2.date < c.date),
              0) AS Average
FROM crossings AS c
ORDER BY date DESC, continent, measure DESC;

两个版本都将受益于(continent, measure, date) 上的索引。

【讨论】:

  • 非常感谢。这真的很有帮助。
猜你喜欢
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-01
  • 1970-01-01
  • 2016-07-11
  • 1970-01-01
  • 2012-11-19
相关资源
最近更新 更多