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)

  

    

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM