Как сгруппировать временные метки в острова (на основе произвольного разрыва)? - PullRequest
2 голосов
/ 07 марта 2019

Рассмотрим этот список дат как timestamptz:

Postgres grouping dates

Я сгруппировал даты вручную, используя цвета: каждая группа отделена от следующейс интервалом не менее 2 минут.

Я пытаюсь измерить, сколько изучил данный пользователь, посмотрев, когда он выполнил какое-либо действие (данные - когда они закончили изучение предложения.) Например:на желтом блоке я бы посчитал, что пользователь учился за один присест, с 14:24 до 14:27, или примерно 3 минуты подряд.

Я вижу, как можно сгруппировать эти даты с помощью языка программирования, просматривая все даты и просматривая разрыв между двумя строками.

У меня вопрос: как бы сгруппировать даты?таким образом с Postgres?

(Поиск «пробелов» в Google или SO приводит к слишком большому количеству не относящихся к делу результатов; я думаю, что мне не хватает словарного запаса для того, что я пытаюсь сделать здесь.)

Ответы [ 2 ]

3 голосов
/ 08 марта 2019

Это будет сделано:

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;

Подзапрос sub записывает step как true, если предыдущая строка находится на расстоянии не менее 2 минут - отсортировано по самому столбцу отметки времени doneв этом случае.

Внешний запрос добавляет скользящее число шагов, фактически номер группы (grp) - объединение агрегатного предложения FILTER с другой оконной функцией.

db <> fiddle здесь

Related:

Об общем предложении FILTER:

0 голосов
/ 12 марта 2019

Основываясь на ответе Эрвина, вот полный запрос для подсчета количества времени, проведенного людьми на этих сессиях / островах:

Мои данные отображаются только тогда, когда люди закончили что-то просматривать, а не когда они начали, а это значит, что мы не знаем, когда сессия действительно началась; и у некоторых островов есть только одна временная метка (что приводит к оценке продолжительности 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...