【问题标题】:How to group timestamps into islands (based on arbitrary gap)?如何将时间戳分组为岛屿(基于任意间隙)?
【发布时间】:2019-07-29 10:58:47
【问题描述】:

将此日期列表视为timestamptz:

我使用颜色手动对日期进行分组:每组与下一组之间至少间隔 2 分钟。

我试图通过查看他们执行操作的时间(数据是他们完成学习句子的时间)来衡量给定用户的学习量。例如:在黄色块上,我认为用户已学习从 14 点 24 分到 14 点 27 分一次,或者大约连续 3 分钟。

我了解如何通过查看所有日期并查找两行之间的间隔,使用编程语言对这些日期进行分组。

我的问题是:如何使用 Postgres 以这种方式对日期进行分组?

(在 Google 或 SO 上寻找“差距”会带来太多不相关的结果;我想我错过了我在这里尝试做的词汇。)

【问题讨论】:

标签: sql postgresql time-series window-functions gaps-and-islands


【解决方案1】:

这样就可以了:

SELECT done, count(*) FILTER (WHERE step) OVER (ORDER BY done) AS grp
FROM  (
   SELECT done
       , (lag(done) OVER (ORDER BY done) <= done - interval '2 min') AS step
   FROM   tbl
   ) sub
ORDER  BY done;

如果前一行至少相隔 2 分钟,则子查询 sub 将 step 记录为 true - 在这种情况下按时间戳列 done 本身排序。

外部查询添加了滚动步数,实际上是组号 (grp) - 将聚合 FILTER 子句与另一个窗口函数结合起来。

db小提琴here

相关:

关于聚合FILTER子句:

【讨论】:

    【解决方案2】:

    以 Erwin 的回答为基础,这里是计算人们在这些会话/岛屿上花费的时间的完整查询:

    我的数据只显示人们完成评论的时间,而不是他们开始的时间,这意味着我们不知道会话何时真正开始;有些岛屿只有一个时间戳(导致估计持续时间为 0)。我通过计算平均审查时间并将其添加到岛屿的总持续时间来考虑这两者。

    这可能对我的用例非常特殊,但我在此过程中学到了一两件事,所以也许这会对以后的人有所帮助。

    -- Returns estimated total study time and average time per review, both in seconds
    SELECT (EXTRACT( EPOCH FROM logged) + countofislands * avgreviewtime) as totalstudytime, avgreviewtime -- add total logged time to estimate for first-review-in-island and 1-review islands
    FROM
        (
        SELECT -- get the three key values that will let us calculate total time spent
          sum(duration) as logged
          , count(island) as countofislands
          , EXTRACT( EPOCH FROM sum(duration) FILTER (WHERE duration != '00:00:00'::interval) )/( sum(reviews) FILTER (WHERE duration != '00:00:00'::interval) - count(reviews) FILTER (WHERE duration != '00:00:00'::interval))  as avgreviewtime
        FROM
            (
            SELECT island, age( max(done), min(done) ) as duration, count(island) as reviews -- calculate the duration of islands
            FROM
                (
                SELECT done, count(*) FILTER (WHERE step) OVER (ORDER BY done) AS island -- give a unique number to each island
                FROM (
                    SELECT -- detect the beginning of islands
                        done,
                        (
                            lag(done) OVER (ORDER BY done) <= done - interval '2 min'
                        ) AS step
                    FROM review
                    WHERE clicker_id = 71 AND "done" > '2015-05-13' AND "done" < '2015-05-13 15:00:00' -- keep the queries small and fast for now
                   ) sub
                ORDER BY done
                ) grouped
            GROUP BY island
            ) sessions
        ) summary
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-28
      • 2022-01-02
      • 1970-01-01
      • 1970-01-01
      • 2020-05-24
      • 1970-01-01
      • 2015-12-24
      • 1970-01-01
      相关资源
      最近更新 更多