viki650

导航

2020中国高校计算机大赛 华为云大数据挑战赛--热身赛--赛题分析、数据理解

一、赛题理解  

  本次比赛任务是利用历史数据并结合地图信息

  预测五和张衡交叉路口  未来一周  周一(2019年2月11日)和周四(2019年2月14日)两天  的5:00-21:00通过wuhe_zhangheng路口4个方向的车流量总和。

  要求模型输出格式如下:   

          {"data":{"resp_data":{"wuhe_zhangheng":[1,4,5,6,4...]}}}

  从5:00开始每5min的预测数据,第一个数据为5:00-5:05的流量值,最后一个数据为20:55-21:00。

  两天的数据按时间先后放在一起,总共有384个数据。

  

  预测输入形式:输入需要预测的日期,按照赛题,输入 {"req_data":["2019-2-11,2019-2-14"]}          

 

  预测数据形式一条道路,一天,四个方向总和,每五分钟预测一次,一天就有60 * 24 / 5 = 288 条记录,输出5:00 - 21:00这16个小时的数据,便是288/24 * 16 = 192 条数据

         预测一天输出结果为 1 * 192 ,两天便是 1 * (192 * 2 )=  1 * 384

 

  注意点预测的是一周中两天的数据,并且这两天都是独立的,没有前后数据,这意味着很难用基于时间顺序流进行预测(需要输入预测值之前一段时间的数据)。

      之前看很多交通预测论文,预测未来数据时,会将连续历史信息作为默认信息

      比如预测T时段的信息,那么T-1、T-2、T-3 ……等前段的数据都是已知的,并且是作为输入送到模型的。

      交通预测理论分析,和物理实验一样,做了很多假设,面对现实,未免会有误差。(同时也说明我的能力太菜了……这个问题应该是可以通过对模型构建来解决,但是我想了几天,脑阔疼)

 

二、原始数据分析

  官方数据:  4周(2019.1.12 – 2019.2.8)深圳龙岗区坂田街道交通流量历史数据 

  数据形式:

    

  

  其中,time为上述格式时间字符串,cross为路口名,direction为车流起始方向,leftFlow是左转车流,straightFlow是直行车流。

  说明

  (1) 十字路口包含四个方向车流数据,此处未全部列出。

  (2) 路口名称分别为:五和路、张衡路、稼先路、隆平路、冲之大道。可以通过但不限于百度地图等地图软件获取地图路网信息。

  (3) 因为右转车流不受信号灯控制,因此未做统计。

 

  数据理解:

    官方说明给出了五个路口,但是实际上有一条冲之-贝尔路口没有说明。

    这些路口分别为:冲之-贝尔路口、冲之-稼先路口、冲之-隆平路口、五和-稼先路口、五和-隆平路口、五和-张衡路口这六条。

    其中四条路口为十字路口、两条路口为三叉路口。所以每一天都会有4*4 + 2*3 = 22个方向的数据,每个方向记录每隔五分钟的交通流,为288条数据。

    官方给出4周,也就是 4 * 7 = 28 天,【28,22,288】

 

三、官方baseline 数据处理

    数据处理方式一般是需要根据模型来变动。

    官方baseline是根据梯度提升决策树进行预测,可以看作是回归模型,根据输入特征值{Xi : i = 1,2,3,……n},获得回归结果(Y)

    baseline只使用了五和-张衡路口的数据,【28,4,288】 = 32256,但是真实提取数据只有29036条数据,说明28天的数据中存在缺失。(若使用时间顺序预测,那么需要补充这部分数据)

    baseline从每一天的日期中,提取出了两个特征,X1 = 星期/6(X1为一个数值,取值范围是【0,1,2,3,4,5,6】/ 6 = 【0,0.167,0.333,0.5,0.667,0.833,1】)

                           X2 = 每5分钟的时刻  【0,5,10,15,……,23*60 + 55】/(24*60) (【1*288】)

                    预测目标:Y = number   【1*288】

    baseline的模型输入:( X1 , X2(i))输出:Y(i)

 

    所以官方baseline数据处理主要就是通过原始数据生成这两个特征。

    首先,读取原始数据,将五和-张衡路口数据中时间和交通流全部提取,大小为【29036,2】      

def read_file(path, filename):
    calfile = os.path.join(path, filename)
    original = pd.read_csv(calfile, header=None)
    data = pd.DataFrame(columns=["time", "number"])
    data["time"] = original[0]
    data["number"] = original[3] + original[4]
    return data
    
# read data of one day
def read_data_day(path, date):
    day_data = pd.DataFrame(columns=["time","number"])
    caldir = os.path.join(path, date)
    # read data of one day
    for f in os.listdir(caldir):
        if re.match(r'wuhe_zhangheng.*\.csv', f):
            day_data = day_data.append(read_file(caldir, f), ignore_index=True)
    return day_data

    随后,将提取出的数据针对时间进行编码,得到两个特征分别对应星期和时刻。并将所有相同特征的数值取平均值。

    注意点:虽然是有四个星期的内容,但是baseline并没有针对第几个星期进行处理。所以不管是第一个星期一,还是第四个星期一,星期编码都是0。

         时刻也是一样。第一个星期一00:05时刻 与 第四个星期一00:05时刻,他们的X1, X2(i)编码是完全相同的。

         同时,五和-张衡路口时十字路口,每个时刻会记录四个不同方向的数据。

         所以对于每个X1、X2(i)会有16 条数据 (四个方向、四个星期),然后将这16个数据平均,变为一个输入

    缺失数据分析:

        上文提到,如果数据完整那么存在28 * 4 * 288 = 32256 条数据。

        按照时刻和星期进行分组,组成【288,7,16】的矩阵,每个元素代表某一个时刻,四个星期的所有方向数据集(总共4周,4个方向,于是有16个数据)

        所以数据应为【288,7,16】。每一个时刻,包含的数据总数应该为【16,16,16,16,16,16,16】

        但是,分析大赛给出数据中有三种形式,分别为

        【12,12,16,16,16,16,16】 前57个时刻

        【12,12,16,16,16,16,12】共223个时刻

        【12,13,16,16,16,16,12】 共8个时刻

        验证:57*(104)+ 223 * (100)+ 8*(101)= 29036 。

        通过缺失数据可以分析,数据量为12个星期,可能说明有一天没有五和-张衡路的数据(一天四个方向数据),或是某几天的数据中缺少五和-张衡路其中一个方向的                                数据。数据量为13则是某几天的数据缺失一个方向的记录。

            

def get_data(path):
    raw_data = pd.DataFrame(columns=["time", "number"])
    for day in os.listdir(path):
        raw_data = raw_data.append(read_data_day(path, day))
    # encode time in raw data to weekday and timeindex(the n minutes of the day)
    df_dt = to_datetime(raw_data.loc[:, "time"], format="%Y/%m/%d %H:%M:%S")
    all_data = pd.DataFrame({
        "weekday": df_dt.dt.weekday/6.0,
        "timeindex": (df_dt.dt.hour * 60 + df_dt.dt.minute)/(24*60.0),
        "number": raw_data["number"].astype(int)}) 
    all_data = all_data.groupby(["weekday", "timeindex"]).sum().reset_index(level = ["weekday", "timeindex"])
        
    return all_data

  模型训练:

    baseline直接引用sklearn中的梯度提升决策树回归GradientBoostingRegressor进行预测。(没了解过,只知道决策树……基础要补课啊 )

  

def train_model():
    X_train, X_test, y_train, y_test = train_test_split(local_data[['weekday','timeindex']], local_data['number'], 
                                                        test_size=0.1, random_state=42)
    print("X_train shape is: " + str(X_train.shape))
    print("X_test shape is: " + str(X_test.shape))
    
    params = {'n_estimators': 500, 'max_depth': 4, 'min_samples_split': 2,   #最优
              'learning_rate': 0.01, 'loss': 'ls'}
    clf = GradientBoostingRegressor(**params)
    clf.fit(X_train, y_train)
    joblib.dump(clf, LOCAL_MODEL_PATH) #模型保存

    y_predict = clf.predict(X_test)  
    
    mse = mean_squared_error(y_test, y_predict)
    print("MSE: %.4f" % mse)

  

    

 

 

posted on 2020-05-21 22:19  viki650  阅读(1172)  评论(0编辑  收藏  举报