当前位置: 首页 > news >正文

自动驾驶数据仓库:时间片合并算法。

在自动驾驶数据仓库,数据都是以时间片的方式进行保存、检索和流转的,但是这些时间片数据的自然时长可能在很大程度上无法直接满足模型的训练和评测,因此时间片的切分、交集计算、合并,前后扩等,就成了对数据进行二次加工、处理的常态化需求,这篇文章给小伙伴们分享一个对连续时间片进行合并的算法

既然是时间片段,那么数据就天然的具备一个属性:时间顺序,因此实现时间片的合并,需要两个步骤:

  • 按时间先后顺序对数据进行排序。

  • 时间上连续的片段进行合并。

下面分别实现这两个步骤。

1、对时间片进行排序

通常情况,数仓数据的获取都来源于检索,根据用户设定的检索条件,比如最近一周内、左转、路口直行、自动驾驶,这些条件,从检索库获取到基础数据,这些基础数据通常都特定的格式,比如:

{"car_id": "京A88888","start_time": 1750859435000,"end_time": 1750859439000,"map_region": "beijing_houchangcun","hardware_version": 2
}

当我们拿到这些数据后,需要通过代码对其进行排序,如上的数据结构,golang无法直接对其进行处理,需要我们自己来实现,首先看一下golang支持的排序,比如如下代码,实现对整型、字符串、浮点型的升序排列

package main
import (
"fmt"
"sort"
)
func main() {
// 对整数切片排序nums := []int{4, 2, 7, 1, 3}sort.Ints(nums)fmt.Println(nums) // 输出: [1 2 3 4 7]
// 对字符串切片排序names := []string{"Zoe", "Alice", "Bob", "John"}sort.Strings(names)fmt.Println(names) // 输出: [Alice Bob John Zoe]
// 对浮点数切片排序floats := []float64{3.2, 1.5, 4.7, 2.1}sort.Float64s(floats)fmt.Println(floats) // 输出: [1.5 2.1 3.2 4.7]
}

降序排列:

// 对整数切片降序排序
nums := []int{4, 2, 7, 1, 3}
sort.Sort(sort.Reverse(sort.IntSlice(nums)))
fmt.Println(nums) // 输出: [7 4 3 2 1]

以上两种方式实现的是对基本数据类型的排序,对于自定义的数据类型无法支持,我们需要自己来实现。

首先定义一个结构体用于存储以上数据:

    
    type DwData struct {CarID string `json:"car_id"`StartTime int64 `json:"start_time"`EndTime int64 `json:"end_time"`MapRegion string `json:"map_region"`HardwareVersion int `json:"hardware_version"`
    }

    第二,实现sort.Interface接口: 

    // 按起始时间排序的 ByStartTime 切片类型
    type ByStartTime []DwDatafunc (a ByStartTime) Len() int           { return len(a) }
    func (a ByStartTime) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
    func (a ByStartTime) Less(i, j int) bool { return a[i].StartTime < a[j].StartTime }

    第三,进行排序:

    type DwData struct {CarID           string `json:"car_id"`StartTime       int64  `json:"start_time"`EndTime         int64  `json:"end_time"`MapRegion       string `json:"map_region"`HardwareVersion int    `json:"hardware_version"`
    }
    // 按起始时间排序的 ByStartTime 切片类型
    type ByStartTime []DwData
    func (a ByStartTime) Len() int           { return len(a) }
    func (a ByStartTime) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
    func (a ByStartTime) Less(i, j int) bool { return a[i].StartTime < a[j].StartTime }
    func main() {clips := []DwData{{CarID:           "1234567890",StartTime:       1200,EndTime:         1205,MapRegion:       "region_a",HardwareVersion: 1,},{CarID:           "1234567890",StartTime:       1100,EndTime:         1105,MapRegion:       "region_a",HardwareVersion: 1,},}sort.Sort(ByStartTime(clips))fmt.Println(clips) // 按起始时间排序后的切片,先打印出StartTime=1100的记录
    }

    排序问题解决后,接下来就可以对相连的时间片进行合并,从而获取到更长的时间片。

    2、对连续的时间片进行合并

    对于以下时间片段,连续的时间片合并后,会新生成四个片段,分别是:

     蓝色一组为一个连续片段、红色一个、绿色一个、黄色一个。

    合并的思路,由于StartTime与EndTime都是单位为毫秒的时间戳,所以只要第一个时间片的EndTime+1000大于等于下一个时间片的StartTime(前提:已排好序),那么这两个时间片段就是连续的,就可以将其合并在一起。

    合并代码如下:

    func MergeClips(adcStatus []DwData) []DwData {adcTags := []DwData{}// 按起始时间排序sort.Sort(ByStartTime(adcStatus))if len(adcStatus) == 0 {return adcTags}// 初始化current变量,用于记录当前正在处理的片段current := adcStatus[0]for _, v := range adcStatus[1:] {if int64(current.EndTime*1000+1000) >= int64(v.StartTime*1000) {// 如果当前片段的结束时间大于等于下一个片段的开始时间,则合并这两个片段current.EndTime = v.EndTime} else {autoTag := DwData{CarID:     v.CarID,StartTime: int64(current.StartTime * 1000),EndTime:   int64(current.EndTime * 1000),}// 当前的时间片和上一个时间片不相邻,则将上一个片段加入到结果切片中adcTags = append(adcTags, autoTag)// 更新当前片段为下一个片段current = v}}autoTag := DwData{CarID:     current.CarID,StartTime: int64(current.StartTime * 1000),EndTime:   int64(current.EndTime * 1000),}adcTags = append(adcTags, autoTag)return adcTags
    }

    上图中的时间片,经过以上的代码处理后,将会变成如下的样子:

     

    c1、c2、c3合并成为一个时间片,c4、c5由于不连续保持原状,c6、c7合并成了一个。

    以上就是时间片合并的全部内容了,学习中有任何问题,可以留言讨论~~~~。

    欢迎各位热爱技术的小伙伴们点个关注,聊聊技术、聊聊跑步、聊聊读书~~~。

     

    往期推荐:

    我在百度的这10年~~

    一个有线上问题带来的知识点:Python日志打印

    一个实际上线的项目:Elastic检索库历史数据清理

    Elastic:索引生命周期管理(Index Lifecycle Management)-减轻ES存储压力

    Python Tortoise ORM库的基础操作介绍

    一个异步架构设计:批量消费RabbitMQ,批量写入Elasticsearch(golang实现)

    一个优秀的rabbitmq消费者(consumer)设计,可直接上线使用。

    Python web框架sanic+tortoise服务框架搭建(MVP版本)

    命令行参数的艺术:Python、Golang、C++技术实现

    supervisor,你理应知道。

    借助tritonserver完成gpt2模型的本地私有化部署

    微信小程序文章列表焕新颜:从丑小鸭到白天鹅的华丽蜕变

    一文揭秘:Golang+Elasticsearch轻松搭建AI时代的图片搜索服务

    protobuf c++开发快速上手指南

    golang线程池ants-你会用了吗

    tfrecord文件介绍、读取、写入介绍

    大同华严寺:受人民爱戴的耿市长还会回来吗?薄伽教藏的合掌漏齿菩萨你知道是谁吗?

    云冈石窟:翻开这本距今1565年、与天地同久长的石头史书,感受北魏王朝雕刻艺术的巅峰之作。

    一个读写excel的简单程序(golang)

    历经沧桑的应县木塔,在风雨中已等你969年。

    从北京到大同,走过600里,跨越1000年。

    跑步的第六年,才真正了解运动的意义

    武汉抗疫英雄汪勇:平凡人的非凡之举。

    李白:为何两次选择做了上门女婿?

    2025年,我要做个自我介绍

     

    http://www.lryc.cn/news/587972.html

    相关文章:

  • ether.js—6—contractFactory以部署ERC20代币标准为例子
  • 0201-solidity基础-区块链-web3
  • OneCode 3.0 VFS客户端驱动(SDK)技术解析:从架构到实战
  • 虚拟货币交易:游走在合法与犯罪的生死线
  • 排序树与无序树:数据结构中的有序性探秘
  • 【【异世界历险之数据结构世界(二叉树)】】
  • 交换类排序的C语言实现
  • 删除当前项目关联的远程仓库(remote)
  • C#结构体:值类型的设计艺术与实战指南
  • 基于ASP.NET+SQL Server实现(Web)排球赛事网站
  • iOS高级开发工程师面试——RunTime
  • JAVA面试宝典 - 《MyBatis 进阶:插件开发与二级缓存》
  • 多尺度频率辅助类 Mamba 线性注意力模块(MFM),融合频域和空域特征,提升多尺度、复杂场景下的目标检测能力
  • 华曦达港股IPO丨AI Home生态构建,开启智能家居新篇章
  • 《Librosa :一个专为音频信号处理和音乐分析设计的Python库》
  • ServBay Windows 1.3.0 更新!新增系统监控与 Nginx 配置升级
  • [spring6: Resource ResourceLoader]-加载资源
  • GPT-4和Claude哪个好
  • UML建模和设计模式——常考点整理
  • VScode链接服务器一直卡在下载vscode服务器,无法连接成功
  • 视频动态范围技术演进:从SDR到HDR的影像革命
  • 【Unity】MiniGame编辑器小游戏(十三)最强射手【Shooter】(下)
  • wpf 实现窗口点击关闭按钮时 ​​隐藏​​ 而不是真正关闭,并且只有当 ​​父窗口关闭时才真正退出​​ 、父子窗口顺序控制与资源安全释放​
  • 单向链表、双向链表、栈、队列复习(7.14)
  • 软件测试中的BUG等级与生命周期详解
  • Java 中的异步编程详解
  • Git根据标签Tag强制回滚版本
  • LVS初步学习
  • LVS(Linux Virtual Server)集群技术详解
  • 【第一章编辑器开发基础第二节编辑器布局_2GUI中滚动列表(2/4)】