1. 寫在前面
時間序列數據廣泛存在於量化交易, 迴歸預測等機器學習應用, 是最常見的數據類型。所以這裏通過墨爾本十年氣溫變化預測的任務來整理一個時間序列數據挖掘的模板,方便以後查閱方便。這個模板可以用在大部分的時間序列預測任務,從股票價格波動,到四季氣溫變化, 從大橋沉降預測,到城市用電預警等。
要進行下面工作的整理:
- 探索性數據挖掘和數據可視化: 繪製折線圖、熱力圖、箱型圖、小提琴圖、滯後圖、自相關圖, 讓枯燥的時間序列數據顏值爆表!
- 對時間做特徵工程:擴展時間數據維度,這個代碼模板也可以作爲時間序列數據的通用預處理模板
- 使用多種機器學習模型建立迴歸擬合模型: 線性迴歸、多項式迴歸、嶺迴歸、隨機森林、神經網絡等,並可視化展示多種模型效果進行對比
通過這次整理,掌握sklearn中常用的工具包以及深度神經網絡的搭建Keras,能夠學習到處理時間序列的方式,裏邊還包含了大量的數據可視化的套路。
由於篇幅原因,這裏可能不會把所有的代碼執行結果展示出來, 只會展示比較重要的結果,畢竟爲了以後方便查閱,太多結果圖像在反而不太好。
OK, let’s go!
2. 導入包和墨爾本1980-1990十年氣溫數據集
# Python的數據處理庫pandas,類似Excel
import pandas as pd
# Python繪圖工具
import matplotlib.pyplot as plt
import seaborn as sns # 這個是matplotlib的進一步封裝,繪製的圖表更加高大上
%matplotlib inline
# 設置繪圖大小
plt.style.use({'figure.figsize':(25, 20)})
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus'] = False # 用來正常顯示負號
import warnings # 過濾警告用
warnings.filterwarnings('ignore')
下面導入墨爾本氣溫數據集
"""讀取數據集"""
df = pd.read_csv('dataset/temperature_min.csv') # csv是通過逗號進行分割,如果不是逗號的數據,需要指定sep
3. 數據探索
3.1 探索性分析初步
第一列Date爲日期,也就是時間序列,我們將第一列的數據類型轉換爲pandas中的datatime日期類型,並將這一列作爲數據的索引,便於後續處理。
df['Date'] = pd.to_datetime(df['Date'])
df = df.set_index('Date')
"""df是pandas裏面的DataFrame數據類型,具有一系列封裝好的屬性和方法。 .後面帶()是方法,不帶()的是屬性"""
然後數據簡單探索
# 再查看一下數據
df.head()
# 查看各列信息
df.info()
# 統計信息
df.describe()
3.2 數據的EDA分析
下面是數據的EDA分析pandas_profiling直接生成數據報告,這個是比賽探索數據神器,在這裏面會看到:
-
總體的數據信息(首先是數據集信息:變量數(列)、觀察數(行)、數據缺失率、內存;數據類型的分佈情況),
-
警告信息
- 要點:類型,唯一值,缺失值
- 分位數統計量,如最小值,Q1,中位數,Q3,最大值,範圍,四分位數範圍
- 描述性統計數據,如均值,模式,標準差,總和,中位數絕對偏差,變異係數,峯度,偏度
-
單變量描述(對每一個變量進行描述)
-
相關性分析(皮爾遜係數和斯皮爾曼係數)
-
採樣查看等
import pandas_profiling as ppf
ppf.ProfileReport(df)
3.3 可視化一些特徵
這裏會通過各種圖進行展示數據的特徵,重點是這些圖怎麼使用。
3.3.1 折線圖
我們把Temp,也就是溫度屬性用折線圖可視化一下:
"""繪製折線圖"""
df['Temp'].plot(figsize=(30,15))
# 設置座標字體大小
plt.tick_params(labelsize=30)
# 生成刻度線網格
plt.grid()
"""折線圖容易產生毛刺,可以換成散點圖"""
看一下結果:
3.3.2 散點圖
"""繪製散點圖"""
df['Temp'].plot(style='k.', figsize=(30,15))
# 設置座標字體大小
plt.tick_params(labelsize=30)
# 生成刻度線網格
plt.grid()
結果:
3.3.3 直方圖
# 設置繪圖大小
plt.style.use({'figure.figsize':(5, 5)})
df['Temp'].plot(kind='hist', bins=20) # bins參數表示橫軸多少等分
# 還有一種
df['Temp'].hist(bins=50)
結果:
3.3.4 堆積面積圖
# 設置繪圖大小
plt.style.use({'figure.figsize':(10, 5)})
df.plot.area(stacked=False)
結果:
3.3.5 核密度估計圖(KDE圖)
# 設置繪圖大小
plt.style.use({'figure.figsize':(10, 5)})
df['Temp'].plot(kind='kde')
結果:
3.3.6 熱力圖
將1982年每一個月的最低氣溫用熱力圖展示出來
關於pandas的重採樣resample
# 設置繪圖大小
plt.style.use({'figure.figsize':(20, 8)})
df['1982'].resample('M').mean().T
sns.heatmap(df['1982'].resample('M').mean().T)
"""爲什麼6月和7月氣溫最低? 因爲墨爾本在澳大利亞,屬於南半球,6月和7月是冬天"""
結果:
3.4 繪製每年氣溫變化的直線圖,箱型圖,熱力圖,小提琴圖
我們剛剛將日期列轉換成了pandas中的datetime類型,我們可以直接通過年份和日期索引選擇指定時間的數據
df['1984']
下面實用pandas的groupby操作,把每年和每天的溫度篩選出來python處理數據的風騷操作pandas 之 groupby&agg
groups = df.groupby(pd.Grouper(freq='1Y'))['Temp']
years = pd.DataFrame()
for name, group in groups:
years[name.year] = group.values
years
這一個要看一下實現了什麼效果:
這個就是把十年的每一天的數據都給做了出來,每一列代表年,每一行是天。下面繪製圖像進行可視化上面這個表:
# 設置繪圖大小
plt.style.use({'figure.figsize':(30, 15)})
years.plot()
# 設置圖例文字大小和圖示大小
plt.legend(fontsize=15, markerscale=15)
# 設置座標文字大小
plt.tick_params(labelsize=15)
結果:
3.4.1 折線圖
"""折線圖"""
years.plot(subplots=True, figsize=(20, 45))
plt.show()
這個會繪製每一年的折線圖,結果就不全顯示了:
3.4.2 箱型圖
這個圖可以很容易的看出離羣點和數據的分佈
"""箱型圖"""
years.boxplot(figsize=(20, 10))
結果如下:
3.4.3 熱力圖
# 設置繪圖大小
plt.style.use({'figure.figsize':(30, 10)})
sns.heatmap(years.T)
"""顏色越黑,表示溫度越低, 顏色越亮,表示溫度越高"""
結果:
plt.matshow(years.T, interpolation=None, aspect='auto')
3.4.4 每一年氣溫的直方圖
"""每一年氣溫的直方圖"""
plt.style.use({'figure.figsize':(30, 22)})
years.hist(bins=15)
這個不做展示。
下面繪製1985年12個月每天的氣溫數據,這個和上面的異曲同工,只不過那個是每一年的每一天,這個是每一個月的每一天。
# 選取1985年12個月每天的氣溫數據
groups_month = df['1985'].groupby(pd.Grouper(freq='1M'))['Temp']
months = pd.concat([pd.DataFrame(x[1].values) for x in groups_month], axis=1)
months = pd.DataFrame(months)
months.columns = range(1, 13)
months
看一下months:
繪製箱型圖:
months.boxplot(figsize=(20, 15))
plt.title('墨爾本1982年每個月最低溫度分佈箱型圖')
繪製熱力圖:
# 設置圖像大小
plt.style.use({'figure.figsize':(5, 8)})
sns.heatmap(months)
plt.title('墨爾本1982年每天最低氣溫分佈熱力圖')
plt.matshow(months, interpolation=None, aspect='auto', cmap='rainbow')
3.4.5 小提琴圖
類似箱型圖,只不過比箱型圖更加高級一些
# 設置圖像大小
plt.style.use({'figure.figsize':(15, 10)})
sns.violinplot(data=months)
plt.title('墨爾本1982年每個月最低氣溫分佈小提琴圖')
# linewidth參數可以控制線寬
sns.violinplot(data=months, linewidth=3)
plt.title('墨爾本1982年每個月最低氣溫分佈小提琴圖')
結果:
3.5 滯後散點圖
時間序列分析假定一個觀測值與前面的觀測值之間存在一定的關係。
相對於某觀察值之前的觀測值被稱爲滯後值,在一個時間步長前的觀測值稱爲滯後一期,在兩個時間步長前的觀測值稱爲滯後二期,依次類推。
比如, 對於1982年8月15日的氣溫數據,8月14日的氣溫爲滯後一期,8月13日的氣溫爲滯後二期
每個觀察值之間和其滯後值之間的關係,可以用滯後散點圖表示
from pandas.plotting import lag_plot
# 設置圖像大小
plt.style.use({'figure.figsize':(10, 10)})
lag_plot(df['Temp'])
plt.title('墨爾本1980-1990年最低氣溫滯後1期散點圖')
結果:
散點圖聚在左下角到右上角,表示與滯後值正相關。 散點圖聚在左上角到右下角,表示與滯後值負相關。 離對角線越緊密,表示相關關係越強。 分散的球狀散點圖表示相關關係微弱。
橫軸表示每天的氣溫,縱軸表示滯後一天的氣溫
通過lag參數控制滯後值
lag_plot(df['Temp'], lag=3)
plt.title('墨爾本1980-1990年最低氣溫滯後3期散點圖')
結果:
還可以繪製不同滯後值對應的散點圖:
"""繪製不同滯後值對應的滯後散點圖"""
lag_list = [1, 2, 3, 5, 10, 20, 50, 100, 150, 180]
plt.style.use({'figure.figsize':(15, 35)})
for i in range(len(lag_list)):
ax = plt.subplot(5, 2, i+1)
ax.set_title('t vs t+' + str(lag_list[i]))
lag_plot(df['Temp'], lag=lag_list[i])
plt.title('墨爾本1980-1990年最低氣溫滯後{}期散點圖'.format(lag_list[i]))
3.6 自相關圖
這個圖還是比較重要的,尤其是對於時間序列來說,可以看出週期和相關性。
代碼如下:
from pandas.plotting import autocorrelation_plot
# 設置圖像大小
plt.style.use({'figure.figsize':(15, 10)})
autocorrelation_plot(df['Temp'])
plt.title('墨爾本1980-1990最低氣溫自相關圖')
# 設置座標文字大小
plt.tick_params(labelsize=10)
plt.yticks(np.linspace(-1, 1, 120))
結果如下:
比如說橫軸是1000, 就表示這個數據集所有數據與它之後1000天的數據的自相關程度。
時間間隔的越遠,溫度之間的自相關程度就擺動着降低。 並且在時間向遠推進的過程中,還會出現週期性的波動,這是由季節的週期性更迭造成的
如果我們隨機取點繪製滯後圖和自相關圖,就會發現完全沒有規律。
# 設置圖像大小
plt.style.use({'figure.figsize':(10, 5)})
a = np.random.randn(100)
a = pd.Series(a)
lag_plot(a)
plt.title("隨機數列的1期滯後散點圖")
結果:
autocorrelation_plot(a)
plt.title('隨機數列的自相關圖')
4. 時間數據的特徵工程
將單純的日期維度擴展成更多維度,構造更多的輸入給模型的特徵,增強數據的可解釋性,更接近人的業務邏輯。
- 哪一年
- 哪一個月
- 星期幾
- 這個月的第幾天
- 月初還是月末
- 一年當中的第幾天
- 一年當中的第幾個月
# 重新調用pandas的read_csv函數讀取數據集文件
df2 = pd.read_csv('dataset/temperature_min.csv')
df2['Date'] = pd.to_datetime(df2['Date'])
下面開始構造數據特徵:
-
把年月日作爲特徵構造成列
# 構造新的一列: 年 df2.loc[:, 'year'] = df2['Date'].apply(lambda x: x.year) # 構造新的一列: 月 df2.loc[:, 'month'] = df2['Date'].apply(lambda x: x.month) # 構造新的一列: 星期幾 df2.loc[:, 'dow'] = df2['Date'].apply(lambda x:x.dayofweek) # 構造新的一列: 一個月第幾天 df2.loc[:, 'dom'] = df2['Date'].apply(lambda x: x.day)
-
是不是週末,是不是週六,是不是週日
# 構造新的三列: 是不是週末、是不是週六、是不是週日 df2.loc[:, 'weekend'] = df2['Date'].apply(lambda x:x.dayofweek > 4) df2.loc[:, 'weekend_sat'] = df2['Date'].apply(lambda x: x.dayofweek == 5) df2.loc[:, 'weekend_sun'] = df2['Date'].apply(lambda x: x.dayofweek == 6)
-
添加上半月和下半月的信息
# 添加上半月和下半月的信息
def half_month(day):
if day in range(1, 16):
return 1
else:
return 2
df2.loc[:, 'half_month'] = df2['dom'].apply(lambda x:half_month(x))
- 添加每個月上中下旬的信息
# 添加每個月上中下旬的信息
def three_part_month(day):
if day in range(1, 11):
return 1
if day in range(11, 21):
return 2
else:
return 3
df2.loc[:, 'three_part_month'] = df2['dom'].apply(lambda x: three_part_month(x))
- 添加每個月四個星期的信息 一個月的第幾個星期
# 添加每個月四個星期的信息 一個月的第幾個星期
def four_week_month(day):
if day in range(1, 8):
return 1
if day in range(8, 15):
return 2
if day in range(15, 22):
return 3
else:
return 4
df2.loc[:, 'four_week_month'] = df2['dom'].apply(lambda x: four_week_month(x))
- 添加節假日信息
# 添加節假日信息
df2.loc[:, 'festival'] = 0
df2.loc[(df2.month==1) & (df2.dom<4), 'festival'] = 1
看看結果,已經從原來的一列氣溫出來了好多個時間特徵,這些對於後面模型會有用。
有了好的特徵纔有好的模型的輸入,並且對於一年的季度還有一個月的上中下旬,這樣用1234表示的定類數據,計算機並不能理解什麼意思,123表示上中下,並不意味着下旬就比上旬大2,所以需要轉成獨熱編碼的形式顯示。
5. 獨熱編碼One-Hot Encoding
獨熱編碼用來將定類數據表示成0-1二進制,便於輸入模型中。
比如,計算機並不認識顏色這一列的“紅”, “黃”, “綠”三個分類,所以我們用“是不是紅色”, “是不是黃色”, “是不是綠色”三列來分開“顏色”這一列特徵。
下面開始做獨熱編碼,但是在做獨熱編碼之前,先保存一份數據
before_dummy_df = df2.copy()
# 構造數據集的特徵
drop_columns = ['Date', 'Temp']
X_before_dummy = before_dummy_df.drop(drop_columns, axis=1)
# 構造數據集的標籤
Y = df['Temp']
"獨熱向量編碼"
columns_to_encoding = ['year', 'month', 'dow', 'dom', 'three_part_month', 'four_week_month']
# 使用pandas的get_dummyise函數對df2指定的列進行獨熱向量編碼
dummy_X = pd.get_dummies(X_before_dummy, columns=columns_to_encoding)
獨熱編碼之後,就會發現數據有了72列特徵
我們通過上面,也構造出了X和Y了,到現在我們有兩組數據:
- 沒有經過獨熱向量編碼操作的數據X_befor_dummy
- 經過獨熱向量編碼的數據dummy_X
共有標籤Y。
有了數據,我們就可以建立模型進行擬合了。
6. 機器學習模型的迴歸擬合
準備好了數據集,就可以進行迴歸擬合了,我們先用幾個常見的解決迴歸問題的機器學習模型:
- 多元線性迴歸
- 多項式迴歸
- 嶺迴歸
- 決策樹和隨機森林
- 支持向量機
- 多層感知機(多層神經網絡)
迴歸模型的評估指標:
6.1 多元線性迴歸擬合
代碼如下:
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
# 劃分訓練集和驗證集
x_train, x_test, y_train, y_test = train_test_split(dummy_X, Y, test_size=0.2, random_state=1, shuffle=True)
lr_reg = LinearRegression()
lr_reg.fit(x_train, y_train)
print('截距', lr_reg.intercept_)
print('斜率(線性模型中各特徵對應的係數)', lr_reg.coef_)
下面把擬合效果進行可視化:
# 繪製氣溫散點圖
df['Temp'].plot(style='k.', figsize=(20, 10))
df.loc[:, '線性迴歸'] = lr_reg.predict(dummy_X)
plt.plot(df['線性迴歸'], 'r.')
# 設置座標文字大小
plt.tick_params(labelsize=20)
# 生成刻度線網格
plt.grid()
結果如下:
6.2 二項多項式迴歸
代碼如下:
from sklearn.preprocessing import PolynomialFeatures
# 構建一個特徵處理器poly_reg, 它能將輸入特徵變成二次的,見上面圖
poly_reg = PolynomialFeatures(degree=2)
# 使用構建的二項多項式特徵處理器poly_reg處理訓練數據dummy_X, 得到包含二次特徵的訓練集X_poly
X_poly = poly_reg.fit_transform(dummy_X)
解釋一下上面的代碼:
構建二次多項式迴歸模型,將上面構造好的X_poly送進去訓練
lin_reg_2 = LinearRegression()
lin_reg_2.fit(X_poly, Y)
# 查看回歸方程係數
print('每個維度對應的係數(斜率):Cofficients: ', lin_reg_2.coef_)
# 查看回歸方程截距
print('截距: intercept', lin_reg_2.intercept_)
df.loc[:, '二次多項式迴歸'] = lin_reg_2.predict(X_poly)
可視化結果:
# 繪製二次多項式迴歸模型擬合的氣溫
df.loc[:, '二次多項式迴歸'] = lin_reg_2.predict(X_poly)
plt.plot(df['二次多項式迴歸'], 'g*')
# 繪製氣溫散點圖
df['Temp'].plot(style='k.', figsize=(20, 13))
# 設置圖例文字大小和圖示大小
plt.legend(fontsize=25, markerscale=5)
# 設置座標文字大小
plt.tick_params(labelsize=25)
# 生成網格
plt.grid()
結果如下:
三次多項式迴歸模型:
# 構建一個特徵處理器ploy_reg3, 它能將輸入特徵變成三次的
ploy_reg3 = PolynomialFeatures(degree=3)
# 使用構建的三次多項式處理訓練集dummy_X, 得到包含三次特徵的訓練集X_poly3
X_poly3 = ploy_reg3.fit_transform(dummy_X)
# 構建三次多項式迴歸模型並訓練
lin_reg_3 = LinearRegression()
lin_reg_3.fit(X_poly3, Y)
df.loc[:, '三次多項式迴歸'] = lin_reg_3.predict(X_poly3)
這個可視化一下,就會發現這個會過擬合:
# 繪製二次多項式迴歸模型擬合的氣溫, 綠色五角星表示
plt.plot(df['二次多項式迴歸'], 'g*')
# 繪製三次多項式迴歸模型擬合的氣溫,紅色三角形表示
plt.plot(df['三次多項式迴歸'], 'r^')
# 繪製氣溫散點圖, 黑色點表示
df['Temp'].plot(style='k.', figsize=(20, 13))
# 設置圖例文字大小和圖示大小
plt.legend(fontsize=15, markerscale=3)
# 設置座標文字大小
plt.tick_params(labelsize=25)
# 生成網格
plt.grid()
"""這個三項式的這個明顯出現了過擬合現象"""
結果:
三次多項式擬合的點與原始數據完全重合,出現了過擬合。
在機器學習中,我們希望模型能大而化之的學習到數據普遍一般規律,而不是對每一個點死記硬背。
因此,線性迴歸中,二項多項式迴歸效果是最好的。
6.3 嶺迴歸
代碼如下:
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(dummy_X, Y, test_size=0.2, random_state=1, shuffle=True)
from sklearn.linear_model import RidgeCV
# alphas 表示正則化強度, 類似之前的代價函數中的λ, cv=5表示5折交叉驗證
ridge = RidgeCV(alphas=[0.2, 0.5, 0.8], cv=5)
ridge.fit(x_train, y_train)
ridge.score(x_test, y_test)
可視化一下:
# 繪製氣溫散點圖, 用黑色點表示
df['Temp'].plot(style='k.', figsize=(20, 13))
df.loc[:, '嶺迴歸'] = ridge.predict(dummy_X)
plt.plot(df['嶺迴歸'], 'g.')
# 設置圖例文字大小和圖示大小
plt.legend(fontsize=15, markerscale=3)
# 設置座標文字大小
plt.tick_params(labelsize=25)
# 生成刻度線網格
plt.grid()
結果:
6.4 決策樹和隨機森林
決策樹和隨機森林的訓練數據不需要進行獨熱向量編碼,所以我們可以直接用X_before_dummy。
"""劃分訓練集和測試集"""
x_train, x_test, y_train, y_test = train_test_split(X_before_dummy, Y, test_size=0.2, random_state=1, shuffle=True)
# 從Python機器學習與數據挖掘工具庫sklearn導入隨機森林迴歸器
from sklearn.ensemble import RandomForestRegressor
# 導入網格搜索交叉驗證,網格搜索可以讓模型參數按我們給定的列表遍歷,找到效果最好的模型
# 交叉驗證可以充分評估模型的準確性
from sklearn.model_selection import GridSearchCV
# 構造參數字典
param_grid = {
'n_estimators': [5, 10, 20, 50, 100, 200], # 決策樹的個數
'max_depth': [3, 5, 7], # 最大樹身, 樹太深會造成過擬合
'max_features': [0.6, 0.7, 0.8, 1] # 決策樹劃分時考慮的最大特徵數
}
rf = RandomForestRegressor()
# 以隨機森林迴歸器爲基礎構造網格搜索迴歸器
grid = GridSearchCV(rf, param_grid=param_grid, cv=3)
# 在訓練集上訓練
grid.fit(x_train, y_train)
"""選取最優參數對應的模型"""
# 查看效果最好的參數
grid.best_params_
# 指定模型效果最好的參數對應的模型
rf_reg = grid.best_estimator_
# 可視化決策樹
from sklearn import tree
import pydotplus
from IPython.display import Image, display
# 從隨機森立中選取一棵決策樹進行可視化
estimator = rf_reg.estimators_[5]
dot_data = tree.export_graphviz(estimator, out_file=None, filled=True, rounded=True)
graph = pydotplus.graph_from_dot_data(dot_data)
display(Image(graph.create_png()))
6.4.1 特徵重要度分析
"""特徵重要度分析"""
rf_reg.feature_importances_
print('特徵排序')
feature_names = ['year', 'month', 'dow', 'dom', 'weekend', 'weekend_sat', 'weedend_sun', 'half_month',
'three_part_month', 'four_week_month', 'festival']
feature_importances = rf_reg.feature_importances_
indics = np.argsort(feature_importances)[::-1]
for index in indics:
print('features %s (%f)' %(feature_names[index], feature_importances[index]))
plt.figure(figsize=(16, 8))
plt.title('隨機森立模型不同特徵的重要度')
plt.bar(range(len(feature_importances)), feature_importances[indics], color='b')
plt.xticks(range(len(feature_importances)), np.array(feature_names)[indics], color='b')
可以看到特徵重要程度:
6.4.2 可視化迴歸擬合效果
# 繪製氣溫散點圖
df['Temp'].plot(style='k.', figsize=(20, 15))
# 繪製隨機森林模型擬合的氣溫
df.loc[:, '隨機森林'] = rf_reg.predict(X_before_dummy)
plt.plot(df['隨機森林'], 'r.')
# 繪製嶺迴歸模型擬合的氣溫
plt.plot(df['嶺迴歸'], 'g.')
plt.legend(fontsize=15, markerscale=3)
plt.tick_params(labelsize=25)
plt.grid()
結果:
6.5 多層神經網絡
神經網絡對輸入特徵的幅度很敏感,我們首先需要將輸入特徵歸一化
from sklearn.preprocessing import scale
feature = scale(X_before_dummy)
X_train, X_val, Y_train, Y_val = train_test_split(feature, Y, test_size=0.2, random_state=1, shuffle=True)
"""訓練集共有2920條數據, 對應2920天的11個時間特徵,標籤爲對應的氣溫"""
# 使用Keras模型快速搭建全連接神經網絡
from keras.models import Sequential
from keras.layers.core import Dense, Dropout
from keras.optimizers import SGD
model = Sequential()
# 第一層,32個神經元,激活函數是relu, 接收11個特徵作爲輸入
model.add(Dense(32, activation='relu', input_shape=(X_train.shape[1], )))
# 第二層,64個神經元,激活函數爲relu
model.add(Dense(64, activation='relu'))
# 迴歸模型的神經網絡最後一層不需要有激活函數,直接用一個神經元線性輸出結果即可
model.add(Dense(1))
# 將模型封裝好,使用均方誤差mse作爲損失函數,使用學習率0.001的隨機梯度下降算法反向傳播,同時平均絕對誤差mae監控模型訓練效果
model.compile(loss='mse', optimizer=SGD(lr=0.001), metrics=['mae'])
# 訓練神經網絡, 每一批128個數據, 訓練50輪(即過50遍完整的訓練集), 每一輪結束後用驗證集評估模型效果
network_history = model.fit(X_train, Y_train, batch_size=128, epochs=50, verbose=1, validation_data=(X_val, Y_val))
繪製結果誤差:
"""繪製訓練過程的mse誤差和mae誤差"""
def plot_history(network_history):
plt.figure()
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.plot(network_history.history['loss'])
plt.plot(network_history.history['val_loss'])
plt.legend(['Training', 'Validation'])
plt.figure()
plt.xlabel('Epochs')
plt.ylabel('Mae')
plt.plot(network_history.history['mean_absolute_error'])
plt.plot(network_history.history['val_mean_absolute_error'])
plt.legend(['Training', 'Validation'])
plt.show()
plot_history(network_history)
模型評估:
model.evaluate(X_val, Y_val, batch_size=10)
結果可視化:
from sklearn.preprocessing import scale
# 繪製氣溫散點圖
df['Temp'].plot(style='k.', figsize=(30, 25))
# 繪製隨機森林模型的迴歸擬合散點圖
plt.plot(df['隨機森林'], 'r.')
# 繪製嶺迴歸模型的迴歸擬合散點圖
plt.plot(df['嶺迴歸'], 'g.')
# 繪製多層感知神經網絡的迴歸擬合散點圖
df.loc[:, "多層神經元"] = model.predict(scale(X_before_dummy))
plt.plot(df['多層神經元'], 'b.')
# 設置圖例文字大小和圖示大小
plt.legend(fontsize=20, markerscale=5)
# 設置座標文字大小
plt.tick_params(labelsize=25)
# 生成刻度線網格
plt.grid()
結果如下:
7. 將回歸擬合的結果文件保存,並比較不同模型的表現
df.to_csv('final_regression.csv', index=True)
result = pd.read_csv('final_regression.csv')
result_analyse = result.describe().copy()
# 給result_analyse新構造一行MSE
result_analyse.loc['MSE', :] = 0
# 構造計算均方誤差的函數
def MSE(yhat, y):
error = np.array(yhat-y)
error_power = np.power(error, 2)
MSE_error = np.sum(error_power) / len(y)
return MSE_error
# 把result_analyse新構造的MSE行填模型的均方誤差
for each in result_analyse.columns:
result_analyse.loc['MSE', each] = MSE(result[each], result['Temp'])
result_analyse
結果如下:
最後是一個模型比較的可視化結果:
plt.figure(figsize=(20, 20))
plt.subplot(421)
plt.title('平均值')
result_analyse.loc['mean', :].plot(kind='bar', color='k')
plt.subplot(422)
plt.title('方差')
result_analyse.loc['std', :].plot(kind='bar', color='y')
plt.subplot(423)
plt.title('最小值')
result_analyse.loc['min', :].plot(kind='bar', color='m')
plt.subplot(424)
plt.title('下四分位數')
result_analyse.loc['25%', :].plot(kind='bar', color='c')
plt.subplot(425)
plt.title('中位數')
result_analyse.loc['50%', :].plot(kind='bar', color='r')
plt.subplot(426)
plt.title('上四分位數')
result_analyse.loc['75%', :].plot(kind='bar', color='g')
plt.subplot(427)
plt.title('最大值')
result_analyse.loc['max', :].plot(kind='bar', color='b')
plt.subplot(428)
plt.title('均方誤差')
result_analyse.loc['MSE', :].plot(kind='bar', color='deepskyblue')
plt.subplots_adjust(wspace=0.07, hspace=0.6) # 調整子圖間距
plt.show()
這裏展示一部分結果:
8. 總結
這裏只是想單純的整理一個時間序列挖掘模板,方便以後查詢使用,畢竟感覺寫的還是挺全的,從數據導入,探索,各種格式化,到特徵工程,建立各種模型,各種模型的評估等,我覺得在後面的任務中,會有借鑑之處,所以先整理下來。
如果想看詳細的講解視頻:
時間序列數據挖掘與機器學習:墨爾本十年氣溫數據集
如果想獲取詳細的代碼和數據集:https://download.csdn.net/download/wuzhongqiang/12245197