引子: 一叶知秋
《淮南子·说山训》:“见一叶落而知岁之将暮。”
宋唐庚《文录》:“唐人有诗云:‘山僧不解数甲子,一叶落知天下秋。’”
古语有云“一叶知秋”,一片叶子的落下可知岁月之更迭。数据亦如是。通过一个清晰直观的数据可视化分析(Data Visualization Analysis)可以让我们窥见既有数据的分布与变化,进而对新数据更好地进行预测。
下面,JerryX就将简单介绍一下自己在热身赛前期做的一点数据可视化分析,讲一讲自己的思考,也希望能够给大家带来一点启发!!如果大家觉得不错,也欢迎大家点赞关注,支持一下哈~有什么问题也欢迎大家及时指出,谢谢!!
首先,在进行数据可视化之前,我们先来回顾一下大赛所给的数据集内容:
数据说明 本次比赛提供4周(2019.1.12 – 2019.2.8)深圳龙岗区坂田街道交通流量历史数据。车流数据格式如下:
其中,time为上述格式时间字符串,cross为路口名,direction为车流起始方向,leftFlow是左转车流,straightFlow是直行车流。
说明:(1) 十字路口包含四个方向车流数据,此处未全部列出。
(2) 路口名称分别为:五和路、张衡路、稼先路、隆平路、冲之大道。
(3) 因为右转车流不受信号灯控制,因此未做统计。
我们在看这一部分的数据说明时,需要注意的是:
1.大赛所给的数据每条代表的是每个时间片内,每个交通路口的每某一方向的左转或者直行的车流量,而我们需要预测的对象是某个路口某一时间片内的所有方向的流量和(右转车辆不考虑)。这里呼应了【上分指南】系列文章第一篇关于baseline分析中提到的一个上分点。官方baseline中仅考虑一个路口的各个方向的车流量均值显然是不太合理的。
2.本次比赛的交通流数据的数据集比较特殊,它的时间范围是19春节假期前的一段时间,所要预测的对象是春节假期后的一段时间内的时间点(20190211与20190214)。所以说无疑是给本次比赛的预测带来了很多的挑战性和随机性。此外测试集时间段并没有给其他的数据,那么我们可以将本次赛题的目标理解为:先用已给的历史数据拟合211与214两天的历史趋势数据,再同时考虑利用一些规则进行历史趋势数据的修正。
进一步的,透过数据可视化的结果,我们可以很清晰地了解到本次比赛交通流数据具有着强周期性与分布的规律性(如下图所示)。同时直观的,我们可以推测这种规律性与每日的早晚高峰时间、是否是周末及是否是春节假期期间具有强关联性。
我们知道时间序列可以拆分为四部分:长期趋势变动T、季节变动S(显式周期,固定幅度、长度的周期波动)、循环变动C(隐式周期,周期长不具严格规则的波动)和不规则变动L
那么考虑到我们实际的交通流量预测的问题,长期的趋势变动T与循环变动C可以通过历史数据提取出来。但是我们又要注意到本次比赛的数据集较小,而所包含的数据又具有着不同的attribute:如:是否是每日的早晚高峰时间、是否是周末及是否是春节假期期间等。那么为了更精确地预测211与214的测试日期的交通流数据,我们就需要构造更具有代表性的数据集来训练我们的预测模型,以更好地减小历史数据中所包含的不规则变动L的影响。
下面我们借助statsmodels工具包,对于不同周次的目标预测路口的交通流量和进行一定的时间序列分解可视化如下:
其中:original是原始时间序列数据,trend是提取的趋势项,Seasonality是指季节性项,residual指的是残差项。
部分代码如下:
import statsmodels.api as sm
import matplotlib.pyplot as plt
import pandas as pd
selected_fea=["weekday","timeindex","east_leftFlow","north_leftFlow","south_leftFlow","west_leftFlow",\
"east_straightFlow","north_straightFlow","south_straightFlow","west_straightFlow","sumFlow","norm_sumFlow"]
weather_dict = {1: "一", 2: "二", 3: "三",4: "四",5: "五",6: "六",7: "日",}
for i in selected_fea:
if i=="sumFlow" and i !="weekday" and i!="time" and i!= "timeindex":
for j in range(7):
cnt=0
plt.figure(figsize=(16,20))
day_list=df[df["weekday"]==j]["day"].drop_duplicates().values
for k in (day_list):
ts=df[(df["weekday"]==j )&(df["day"]==k)][i].values
rd = sm.tsa.seasonal_decompose(ts, freq=12)
trend = rd.trend
seasonal = rd.seasonal
residual = rd.resid
plt.subplot(411)
plt.plot( ts, label='Original',alpha=0.7)
plt.legend(loc='best')
plt.subplot(412)
plt.plot( trend, label='Trend',alpha=0.7)
plt.legend(loc='best')
plt.subplot(413)
plt.plot( seasonal,label='Seasonality',alpha=0.7)
plt.legend(loc='best')
plt.subplot(414)
plt.plot( residual, label='Residuals',alpha=0.7)
plt.legend(loc='best')
ts = df.groupby(["weekday", "timeindex"]).mean().reset_index(level = ["weekday", "timeindex"])
ts=ts[ts["weekday"]==j ][i].values
rd = sm.tsa.seasonal_decompose(ts, freq=12)
trend = rd.trend
seasonal = rd.seasonal
residual = rd.resid
plt.subplot(411)
plt.plot( ts, label="mean_"+'Original',marker=".")
plt.legend(loc='best')
plt.grid(True,ls='--')
plt.subplot(412)
plt.plot( trend, label="mean_"+'Trend',alpha=0.7,marker=".")
plt.legend(loc='best')
plt.grid(True,ls='--')
plt.subplot(413)
plt.plot( seasonal,label="mean_"+'Seasonality',alpha=0.7,marker=".")
plt.legend(loc='best')
plt.grid(True,ls='--')
plt.subplot(414)
plt.plot( residual, label="mean_"+'Residuals',alpha=0.7,marker=".")
plt.legend(loc='best')
plt.grid(True,ls='--')
ts = df[df["month"]==1].groupby(["weekday", "timeindex"]).mean().reset_index(level = ["weekday", "timeindex"])
ts=ts[ts["weekday"]==j ][i].values
rd = sm.tsa.seasonal_decompose(ts, freq=12)
trend = rd.trend
seasonal = rd.seasonal
residual = rd.resid
plt.subplot(411)
plt.plot( ts, label="month_1_mean_"+'Original',alpha=0.7,marker=".")
plt.legend(loc='best')
plt.grid(True,ls='--')
plt.subplot(412)
plt.plot( trend, label="month_1_mean_"+'Trend',alpha=0.7,marker=".")
plt.legend(loc='best')
plt.grid(True,ls='--')
plt.subplot(413)
plt.plot( seasonal,label="month_1_mean_"+'Seasonality',alpha=0.7,marker=".")
plt.legend(loc='best')
plt.grid(True,ls='--')
plt.subplot(414)
plt.plot( residual, label="month_1_mean_"+'Residuals',alpha=0.7,marker=".")
plt.legend(loc='best')
plt.grid(True,ls='--')
plt.tight_layout()
plt.suptitle("周"+str(j+1)+"_"+i,fontsize = 20, ha='center')
plt.show()
plt.close()
简单的可视化可以让我们注意到以下几点:
1.工作日单日的数据具有着较好的每日波动变化一致性(分时总流量可以见下图)
2.不同日期的时间序列数据随着春节的临近而具有着总体的流量分布递减的趋势
3.既有的时间序列中存在一定的缺失项,有待我们去有技巧性的填补或删去
4.春节的调休导致节前的周末的单日车流量变化情况也出现了早晚高峰的双峰状特征。所以按照周末与非周末划分后,还需要考虑到调休的影响。直接采用datetime得到的周次特征需要修正。
5.交通流数据在双峰之间的时间段(下午)较为平缓,或许有较好的一致性
6.一些数据中的异常的波动或许与一些大事件(如华为年会等)有关,这样的数据可以理解为历史时间序列中的干扰项,对于我们未来的模型预测可能意义不是很大。需要斟酌一下数据集的清洗。
=这里是分割线=========================================
先分析到这里,觉得不错的可以点赞关注哈!也欢迎大家持续关注JerryX的博客,希望能够与大家一同学习、成长!!!如有什么问题,更欢迎大家的批评指正!!【上分指南】系列文章也将持续更新哦~
往期【上分指南】与赛题分析:
[上分指南] 2020华为云大数据挑战赛热身赛如何“未卜先知”测试集数据的分布特点?探索思路分享第二弹
[上分指南] 2020华为云大数据挑战赛热身赛如何轻松快速提高10分?baseline简单解读与优化思路分享第一弹
2020中国高校计算机大赛·华为云大数据挑战赛热身赛_交通流量预测赛题分析4.26更新版(持续更新,欢迎关注!!!)