1. 程式人生 > >一個預測自行車租賃的簡單例子

一個預測自行車租賃的簡單例子

自行車資料集給出了2015年8月每天的自行車租賃的數目,每隔3小時統計一次,要求預測給定日期和時間,出租自行車的數目。

1.載入資料

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import mglearn

citibike = mglearn.datasets.load_citibike()

print("Citibike data:\n{}".format(citibike.head()))

下面繪出整個月租車數目的視覺化圖形:

plt.figure(figsize=(10, 3))
xticks = pd.date_range(start=citibike.index.min(), end=citibike.index.max(),
                       freq='D')
plt.xticks(xticks.astype("int"), xticks.strftime("%a %m-%d"), rotation=90, ha="left")
plt.plot(citibike, linewidth=1)
plt.xlabel("Date")
plt.ylabel("Rentals")

 

在對時間序列的預測任務進行評估時,我們通常希望從過去學習並預測未來,也就是說,在劃分訓練集和測試集時,我們希望使用某個特定日期之前的所有資料作為訓練集,該日期之後的所有資料作為測試集。在這裡,我們使用前184個數據點(對應前23天0)作為訓練集,剩餘的64個數據點(對應於後8天)作為測試集。

在我們的預測任務中,我們使用的唯一特徵就是某一天租車數量對應的日期和時間,在計算機上儲存日期常用的方式是POSIX時間,它是從1970年1月1日00:00:00起至現在的總秒數。

2.採用POSIX特徵訓練模型

首先匯入資料:

# extract the target values (number of rentals)
y = citibike.values
# convert to POSIX time by dividing by 10**9
X = citibike.index.astype("int64").values.reshape(-1, 1) // 10**9

然後定義一個函式eval_features(features,target,regressor)將資料劃分成訓練集和測試集,構建模型並將結果視覺化。

# use the first 184 data points for training, the rest for testing
n_train = 184

# function to evaluate and plot a regressor on a given feature set
def eval_on_features(features, target, regressor):
    # split the given features into a training and a test set
    X_train, X_test = features[:n_train], features[n_train:]
    # also split the target array 
    y_train, y_test = target[:n_train], target[n_train:]
    regressor.fit(X_train, y_train)
    print("Test-set R^2: {:.2f}".format(regressor.score(X_test, y_test)))
    y_pred = regressor.predict(X_test)
    y_pred_train = regressor.predict(X_train)
    plt.figure(figsize=(10, 3))

    plt.xticks(range(0, len(X), 8), xticks.strftime("%a %m-%d"), rotation=90,
               ha="left")

    plt.plot(range(n_train), y_train, label="train")
    plt.plot(range(n_train, len(y_test) + n_train), y_test, '-', label="test")
    plt.plot(range(n_train), y_pred_train, '--', label="prediction train")

    plt.plot(range(n_train, len(y_test) + n_train), y_pred, '--',
             label="prediction test")
    plt.legend(loc=(1.01, 0))
    plt.xlabel("Date")
    plt.ylabel("Rentals")

接著,以POSIX時間特徵,在隨機森林上訓練模型:

from sklearn.ensemble import RandomForestRegressor
regressor = RandomForestRegressor(n_estimators=100, random_state=0)
eval_on_features(X, y, regressor)

在訓練集上預測結果相當好,這符合隨機森林通常的表現。但對於測試集來說,預測結果是一條常數直線 ,說明什麼都沒有學到。問題在於特徵和隨機森林的組合。測試集中POSIX時間特徵的值超出了訓練集中特徵的取值範圍:測試集中的資料點的時間戳要晚於訓練集中的所有資料點。樹以及隨機森林無法外推到訓練集之外的特徵範圍。結果就是模型只能預測訓練集中最近資料點的目標值,即最後一天觀測到資料的時間。

通過觀察訓練集中租車數量的影象,我們發現兩個因素非常重要:一天內的時間與一週的星期幾。因此,我們來研究這兩個特徵。

3.使用每天時刻作為特徵

X_hour = citibike.index.hour.values.reshape(-1, 1)
eval_on_features(X_hour, y, regressor)

4.新增一週星期幾作為特徵

X_hour_week = np.hstack([citibike.index.dayofweek.values.reshape(-1, 1),
                         citibike.index.hour.values.reshape(-1, 1)])
eval_on_features(X_hour_week, y, regressor)

 

此時模型的預測效果很好,模型學到 的內容可能是8月前23天中星期幾與時刻每種組合的平均租車數量。這實際上不需要像隨機森林那樣複雜的模型,我們嘗試一下LinearRegression: