# 基于 DolphinDB 机器学习的出租车行程时间预测 DolphinDB 集高性能时序数据库与全面的分析功能为一体,可用于海量结构化数据的存储、查询、分析、实时计算等,在工业物联网场景中应用广泛。本文以纽约出租车行程时间预测为例,介绍如何使用 DolphinDB 训练机器学习模型,并进行实时数据的预测,为基于智能网联汽车的车联网企业提供基于机器学习方法的即时预测方案。 - [1. 概要](#1-概要) - [2. 数据介绍](#2-数据介绍) - [2.1 数据来源及训练方法](#21-数据来源及训练方法) - [2.2 数据特征](#22-数据特征) - [2.3 数据存储](#23-数据存储) - [3. 模型构建](#3-模型构建) - [3.1 数据预处理](#31-数据预处理) - [3.2 位置信息主成分分析(PCA)](#32-位置信息主成分分析pca) - [3.3 位置信息聚类(KMeans)](#33-位置信息聚类kmeans) - [3.4 新特征构建](#34-新特征构建) - [3.5 模型训练(XGBoost)](#35-模型训练xgboost) - [3.6 模型评价](#36-模型评价) - [4. 行程时间实时预测](#4-行程时间实时预测) - [4.1 场景描述](#41-场景描述) - [4.2 实时数据模拟及预测](#42-实时数据模拟及预测) - [4.3 Grafana 实时监控](#43-grafana-实时监控) - [4.4 数据持久化](#44-数据持久化) - [5. 总结](#5-总结) - [6. 附录](#6-附录) - [6.1 测试环境](#61-测试环境) - [6.2 模型代码](#62-模型代码) ## 1. 概要 随着手机移动应用与网约车平台的迅速发展,网约车出行逐渐成为城市生活中一种重要的出行方式。相较其他出行方式而言,选择网约车的乘客对出行时效性有更高的要求,本文将基于乘客上车时间及上下车地点等静态信息,使用 DolphinDB 机器学习方法训练模型,预测网约车行程时间。 在此基础上,本文将介绍如何使用 [DolphinDB 流数据处理系统](https://gitee.com/dolphindb/Tutorials_CN/blob/master/streaming_tutorial.md)对业务系统产生的持续增长的网约车订单动态数据进行实时的收集、清洗、统计、入库,并实时展示行程时间预测结果。
行程时间实时预测流程
## 2. 数据介绍 ### 2.1 数据来源及训练方法 本文训练和预测采用 [Kaggle ](https://www.kaggle.com/competitions/nyc-taxi-trip-duration)提供的来自纽约出租车委员会的数据集,训练方法参考了获奖者 [beluga](https://www.kaggle.com/code/gaborfodor/from-eda-to-the-top-lb-0-367) 的模型,使用 DolphinDB 对原始数据进行数据预处理,完成位置信息主成分分析(PCA, Principal Component Analysis)、位置信息聚类(KMeans)、新特征构建等工作,并使用 DolphinDB XGBoost 插件完成模型训练及行程时间预测。 为对比 DolphinDB 在机器学习上的性能,本文使用 Python Scikit-Learn 库及 XGBoost 在同一环境下进行了模型训练和预测,DolphinDB 在训练耗时、模型精度等方面均有良好表现。 ### 2.2 数据特征 该数据集预先分为训练数据集及测试数据集,训练数据集共包含 1458644 条数据,测试数据集共包括 625134 条数据;训练数据集共包含以下 11 列信息。 | **列名** | **列类型** | **说明** | **实例** | | :----------------- | :--------- | :--------------------------- | :----------------- | | id | SYMBOL | 行程的唯一标识 | id2875421 | | vendor_id | INT | 行程记录提供商代码 | 2 | | pickup_datetime | DATETIME | 出租车计价器开启时间 | 2016/3/14 17:24:55 | | dropoff_datetime | DATETIME | 出租车计价器关闭时间 | 2016/3/14 17:32:30 | | passenger_count | INT | 乘客数量 | 1 | | pickup_longitude | DOUBLE | 出租车计价器开启位置经度 | -73.98215484619139 | | pickup_latitude | DOUBLE | 出租车计价器开启位置纬度 | 40.76793670654297 | | dropoff_longitude | DOUBLE | 出租车计价器关闭位置经度 | -73.96463012695312 | | dropoff_latitude | DOUBLE | 出租车计价器关闭位置纬度 | 40.765602111816406 | | store_and_fwd_flag | CHAR | 标识来源是否为存储的历史数据 | N | | trip_duration | INT | 行程时间(按秒计) | 455 | 行程时间预测的目标列为上表中 trip_duration 列,即 dropoff_datetime 与 pickup_datetime 之差。测试数据集用于预测,故其列信息不包括 dropoff_datetime 及 trip_duration 列,测试数据集中行程标识、位置等列属性同上表。 上表的数据类型中,SYMBOL 类型是 DolphinDB 中一种特殊的字符串类型,在系统内部的存储结构为一个编码字典,DATETIME 类型为包含了日期和时刻的时间类型。 DolphinDB 支持 `loadText` 方法读取 csv 等数据存储文件到内存表,用户可以 `schema` 函数获取表的特征信息。DolphinDB 也支持使用 SQL 语句完成数据的查询。 ``` train = loadText("./taxidata/train.csv") train.schema().colDefs select count(*) from train select top 5 * from train ``` ### 2.3 数据存储 将数据加载到内存表后,可以将训练数据与测试数据导入 DolphinDB 数据库中,便于后续数据的读取与模型的训练,数据导入分布式数据库的操作详见 [database.md · dolphindb/Tutorials_CN - Gitee](https://gitee.com/dolphindb/Tutorials_CN/blob/master/database.md)。 ## 3. 模型构建 本节介绍行程时间预测模型的构建方法。 行程时间预测模型的构建分多个过程,一是预处理原始数据,对可能存在的空值进行转换,并将字符等非数值型数据转换为可用于模型训练的数值型数据;二是优化位置信息,原始数据中的纬度经度信息集中在 40.70 °N 至 40.80 °N 及 73.94 °W 至 74.02 °W 之间,数据间位置特征差异不够显著,使用主成分分析、聚类方法处理可以提取到特征更明显的信息;三是新特征的构建,位置信息和时间信息是订单数据的两个关键维度,通过计算可以在位置信息基础上得到方位、距离信息,提取更多空间特征,而组合不同类别的位置信息和时间信息也可以得到更复杂的特征,有利于模型学习深层次的时空规律。 ### 3.1 数据预处理 在模型训练过程中,首先需要检查数据集是否包含空值,本训练数据集与测试数据集均不包含空值,若存在缺失值,还需要删除、插补等操作解决缺失数据问题。 其次,需要检查数据集数据类型,原始数据往往包含文本/字符数据,由 1.3 节表可知,本数据集中 store_and_fwd_flag 列为字符型数据,pickup_datetime 及 dropoff_datetime 列为日期时间类型数据,为充分利用这些信息训练模型,需要将其转化为数值型数据。 此外,考虑到该数据测试集评价指标为均方根对数误差(Root Mean Squared Logarithmic Error, RMSLE),同时,最大行程时间接近 1000 小时,离群值会影响模型训练效果,对行程时间取对数作为预测值,在评价时(见 3.6 节)可以直接使用均方根误差(Root Mean Squared Error, RMSE)指标。
RMSE
DolphinDB 提供多种计算函数,可以帮助用户快速实现数据处理。DolphinDB 提供 `isNull()` 方法用于判断空值,配合 `sum()` 等聚合函数使用可以快速完成整表数据的查询;提供类似于条件运算符的 `iif()` 方法简化 if-else 语句;`date()`、`weekday()`、`hour()` 等方法可以提取时间、日期数据的不同特征,简洁高效;类似于 Python 等编程语言,DolphinDB 支持方括号 ([]) 索引,简化了表的查找、更新和插入。 ``` sum(isNull(train)) // 0,不含空值 trainData[`store_and_fwd_flag_int] = iif(trainData[`store_and_fwd_flag] == 'N', int(0), int(1)) // 将字符N/Y转化为0/1值 trainData[`pickup_date] = date(trainData[`pickup_datetime]) // 日期 trainData[`pickup_weekday] = weekday(trainData[`pickup_datetime]) // 星期* trainData[`pickup_hour] = hour(trainData[`pickup_datetime]) // 小时 trainData[`log_trip_duration] = log(double(trainData[`trip_duration]) + 1)// 对行程时间取对数,log(trip_duration+1) select max(trip_duration / 3600) from trainData // 训练集上最大行程时间为979h ``` ### 3.2 位置信息主成分分析(PCA) 原始数据中的纬度经度信息集中在 40.70 °N 至 40.80 °N 及 73.94 °W 至 74.02 °W 之间,数据间位置特征差异不够显著,使用 PCA 来转换经度和纬度坐标,有助于 XGBoost 决策树的拆分,DolphinDB PCA 函数使用详见 [pca — DolphinDB 2.0 documentation](https://www.dolphindb.cn/cn/help/FunctionsandCommands/FunctionReferences/p/pca.html)。 DolphinDB PCA 返回的结果是一个字典,包含 components、explainedVarianceRatio、singularValues 三个键,分别代表对应大小为 size(colNames)*k 的主成分分析矩阵、前 k 个主成分每个特征的方差贡献率、主成分方差(协方差矩阵特征值)。可通过主成分分析矩阵转换待处理数据,详见 [Scikit-Learn PCA.transform()](https://github.com/scikit-learn/scikit-learn/blob/9aaed4987/sklearn/decomposition/_base.py#L100)。 可从中取若干数据绘制经度 - 纬度散点图观察 PCA 结果。 经处理,位置坐标分散在原点附近。
PCA 前上客位置信息
PCA 后上客位置信息
`pca()` 接收一个或多个数据源为参数,对指定列中的数据进行主成分分析,用户可通过 `table()` 方法创建内存表,用于 PCA;DolphinDB 也提供了 `dot()`、`repmat()` 等矩阵乘法、矩阵堆叠方法,用户可使用内置函数快速完成矩阵运算,处理位置信息。 ``` PCApara = table(trainData[`pickup_latitude] as latitude, trainData[`pickup_longitude] as longitude) pca_model = pca(sqlDS(