如何分析时间序列数据并删除“重复”记录

t0ybt7op  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(451)

我有一个大的数据集(~2m行),描述车辆在大型停车场周围移动时的数据。也就是说,每辆车通过结构中的多个“区域”时都会被扫描。它看起来像这样:

  1. +--------+----------------+----------+---------------------+
  2. | id | zone_camera_id | plate | timestamp |
  3. +--------+----------------+----------+---------------------+
  4. | 453445 | Z05-C01 | AAAABBBB | 2020-06-25 08:02:23 |
  5. | 453446 | Z05-C02 | AAAABBBB | 2020-06-25 08:04:55 |
  6. | 453447 | Z03-C01 | CCCCDDDD | 2020-06-25 08:05:19 |
  7. | 453448 | Z02-C02 | AAAABBBB | 2020-06-25 08:05:23 |
  8. | 453449 | Z07-C03 | CCCCDDDD | 2020-06-25 08:09:08 |
  9. | 453450 | Z07-C04 | CCCCDDDD | 2020-06-25 08:10:01 |
  10. | 453451 | Z04-C04 | AAAABBBB | 2020-06-25 08:11:44 |
  11. | 453452 | Z04-C01 | AAAABBBB | 2020-06-25 08:11:59 |
  12. | 453453 | Z04-C03 | AAAABBBB | 2020-06-25 08:12:06 |
  13. | 453454 | Z05-C03 | AAAABBBB | 2020-06-25 08:13:00 |
  14. +--------+----------------+----------+---------------------+
  15. ``` `camera_id` 分解如下: `<Zone ID>-<Camera ID>` ,和 `<Camera ID>` 通常不相关;被检测到的车辆 `Z05-C01` 等同于被检测到的同一辆车 `Z05-C04` .
  16. 我可以很快 `GROUP BY` 这个 `zone_camera_id` 使用 `LEFT()` ,如下所示:

SELECT Count(*) AS scan_count,
LEFT(zone_camera_id, 3) AS zone
FROM vehicle_scans
WHERE plate = 'AAAABBBB'
GROUP BY LEFT(zone_camera_id, 3)

  1. 我看到了:

+------------+------+
| scan_count | zone |
+------------+------+
| Z05 | 3 |
| Z02 | 1 |
| Z04 | 3 |
+------------+------+

  1. 这是一个很好的信息,但它并不能提供任何洞察的“路径”的司机采取。此查询不知道时间顺序,因此如果驱动程序在 `Z02` ,转到 `Z05` ,然后*回到* `Z02` ,那些 `Z02` 扫描结果将集中在一起。
  2. 我想做的是删除“重复”扫描,其中一个司机被扫描多次在同一个区域在一行(没有离开该区域,如 `ID=453445,453446` 但不是 `ID=453454` 当司机回来的时候),但从未离开过这个区域。基本上,我想知道当一个司机进入一个区域和退出一个区域,没有访问一个不同的区域在这段时间。
  3. 我希望确定每辆车在每个区域持续花费的时间,即使它们稍后返回该区域,如下所示:

+---------+------------+---------------------+---------------------+
| zone_id | scan_count | enter_time | exit_time |
+---------+------------+---------------------+---------------------+
| Z05 | 2 | 2020-06-25 08:02:23 | 2020-06-25 08:04:55 |
| Z02 | 1 | 2020-06-25 08:05:23 | 2020-06-25 08:05:23 |
| Z04 | 3 | 2020-06-25 08:11:44 | 2020-06-25 08:12:06 |
| Z05 | 1 | 2020-06-25 08:13:00 | 2020-06-25 08:13:00 |
+---------+------------+---------------------+---------------------+
``` Z05 出现两次,因为他们访问了该区域两次,中间还有两次访问。
这就是我所尝试的,使用 Min() 以及 Max() :

  1. SELECT Count(*) AS scan_count,
  2. LEFT(camera_zone_id, 3) AS zone_id,
  3. Min(timestamp) AS enter_time,
  4. Max(timestamp) AS exit_time
  5. FROM vehicle_scans
  6. WHERE plate = 'AAAABBBB'
  7. GROUP BY LEFT(camera_zone_id, 3)
  8. ORDER BY enter_time

这是一个很好的信息,它符合我想要的输出结构,但是 Min() 以及 Max() 值反映该区域内扫描的绝对最小和最大时间戳,而不是单一区域中扫描序列的最小和最大时间戳。在上述情况下,例如 AAAABBBB ,车辆开始于 Z05 ,访问另外两个区域,然后返回 Z05 . 上面的查询使用第一个 Z05 扫描最后一个 Z05 扫描,即使还有两个区域被访问( Z02 以及 Z04 )介于两者之间。我正在寻找每一个不间断的“访问”在自己的行区域,删除“重复”扫描,而他们继续得到扫描 LEFT(camera_zone_id, 3) .
有没有一种基于sql的方法可以不间断地对这些行进行分组?
谢谢您!

3hvapo4f

3hvapo4f1#

这可能是一个缺口和孤岛问题——但你需要通过板块来巩固这个问题。
行号的不同很方便:

  1. select plate, left(camera_zone_id, 3), min(timestamp), max(timestamp)
  2. from (select vs.*,
  3. row_number() over (partition by plate, left(camera_zone_id, 3) order by timestamp) as seqnum_pc,
  4. row_number() over (partition by plate order by timestamp) as seqnum_p
  5. from vehicle_scans vs
  6. ) vs
  7. group by plate, (seqnum_pc - seqnum_p)

相关问题