1、模塊導入
import tensorflow as tf
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import os
import pandas as pd
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import r2_score
from tensorflow.keras import utils,losses,layers,Sequential
from tensorflow.keras.callbacks import ModelCheckpoint,TensorBoard
mpl.rcParams['figure.figsize'] = (10, 8)
mpl.rcParams['figure.dpi'] = 150
mpl.rcParams['axes.grid'] = False
2、加載數據集、預處理
使用 Max Planck Institute for Biogeochemistry 的天氣時間序列數據集。 該數據集包含14個不同的特徵,例如氣溫,大氣壓力和溼度。從2003年開始,每10分鐘收集一次。爲了提高效率,本文僅使用2009年至2016年之間收集的數據。
下載數據集:
zip_path = tf.keras.utils.get_file(
origin='https://storage.googleapis.com/tensorflow/tf-keras-datasets/jena_climate_2009_2016.csv.zip',
fname='jena_climate_2009_2016.csv.zip',
extract=True)
csv_path, _ = os.path.splitext(zip_path)
加載數據集:
df = pd.read_csv(csv_path,parse_dates=['Date Time'],index_col=['Date Time'])
df.head()
p (mbar) | T (degC) | Tpot (K) | Tdew (degC) | rh (%) | VPmax (mbar) | VPact (mbar) | VPdef (mbar) | sh (g/kg) | H2OC (mmol/mol) | rho (g/m**3) | wv (m/s) | max. wv (m/s) | wd (deg) | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Date Time | ||||||||||||||
2009-01-01 00:10:00 | 996.52 | -8.02 | 265.40 | -8.90 | 93.3 | 3.33 | 3.11 | 0.22 | 1.94 | 3.12 | 1307.75 | 1.03 | 1.75 | 152.3 |
2009-01-01 00:20:00 | 996.57 | -8.41 | 265.01 | -9.28 | 93.4 | 3.23 | 3.02 | 0.21 | 1.89 | 3.03 | 1309.80 | 0.72 | 1.50 | 136.1 |
2009-01-01 00:30:00 | 996.53 | -8.51 | 264.91 | -9.31 | 93.9 | 3.21 | 3.01 | 0.20 | 1.88 | 3.02 | 1310.24 | 0.19 | 0.63 | 171.6 |
2009-01-01 00:40:00 | 996.51 | -8.31 | 265.12 | -9.07 | 94.2 | 3.26 | 3.07 | 0.19 | 1.92 | 3.08 | 1309.19 | 0.34 | 0.50 | 198.0 |
2009-01-01 00:50:00 | 996.51 | -8.27 | 265.15 | -9.04 | 94.1 | 3.27 | 3.08 | 0.19 | 1.92 | 3.09 | 1309.00 | 0.32 | 0.63 | 214.3 |
如上所示,每10分鐘記錄一次觀測值,一個小時內有6個觀測值,一天有144(6x24)個觀測值。 給dataset插入新列,列爲Data Time列的相應時間值
3、數據可視化
畫圖看相關性,提取有效特徵集
這裏選擇p (mbar)、Tdew (degC)、max. wv (m/s)作爲T (degC)和rh (%)的特徵
plt.figure(figsize=(16,8))
#作圖輔助庫
sns.lineplot(x='p (mbar)',y='T (degC)',data=df[:10000])
plt.show()
plt.figure(figsize=(16,8))
sns.lineplot(x='Tdew (degC)',y='T (degC)',data=df[:10000])
plt.show()
plt.figure(figsize=(16,8))
sns.lineplot(x='max. wv (m/s)',y='T (degC)',data=df[:50000])
plt.show()
以上是看T (degC)和p (mbar)、Tdew (degC)、max. wv (m/s),的關係
給dataset插入新列,列爲Data Time列的相應時間值
df['year']=df.index.year
df['hour']=df.index.hour
df['month']=df.index.month
時間與溫度的點圖
plt.figure(figsize=(16,8))
sns.pointplot(x='hour',y='T (degC)',data=df[0:50000],hue='month')
plt.show()
時間與溼度的點圖
plt.figure(figsize=(16,8))
sns.pointplot(x='hour',y='rh (%)',data=df[0:50000],hue='month')
plt.show()
由於溫度與每日的小時變化有關係,而且0-23作爲一個循環,所以用三角函數提取週期信息,sin和cos同時使用是因爲確保24小時爲一個週期
df['sin(h)']=[np.sin((x) * (2 * np.pi / 24)) for x in df['hour']]
df['cos(h)']=[np.cos((x) * (2 * np.pi / 24)) for x in df['hour']]
df
4、數據預處理
切分數據集
#定義切分函數,x是選取的特徵組成的例表,y是標籤列(x=dataset[future=] ,y=dataset['T (degC)'])
#train_dataset,train_labels=multivariate_data(x_train,y_train,0,100000,3,1,1,True)
#上面的一個使用的意思就是:從0開始數到10萬,按照3條x數據作爲一個元素放入data-》1條y數據作爲一個元素存入labels,step=1表示每一條數據就按照上面包裝一次,比如data[0]=x[0,1,2]->labels[0]=y[3];data[1]=x[1,2,3]->labels[1]=y[4];
#single_step意思是隻預測目標的一個未來狀態,只預測後1小時,設置爲false可以預測未來0到target_size小時內的溫度。
def multivariate_data(x,y, start_index, end_index, history_size,target_size, step, single_step):
data = []
labels = []
start_index = start_index + history_size
if end_index is None:
end_index = len(dataset) - target_size
for i in range(start_index, end_index):
indices = range(i-history_size, i, step) # step表示滑動步長
mid_data=x.iloc[indices]
data.append(mid_data)
if single_step:
mid_data=y.iloc[i+target_size]
labels.append(mid_data)
else:
labels.append(y.iloc[i:i+target_size])
return np.array(data), np.array(labels)
數據歸一化
future=['sin(h)','cos(h)','month','max. wv (m/s)','p (mbar)','T (degC)','rh (%)']
#數據歸一化,由於sin和cos本來就是-1到1,不用歸一化
for col in future:
scaler=MinMaxScaler()
if(col not in ['sin(h)','cos(h)']):
df[col]=scaler.fit_transform(df[col].values.reshape(-1,1))
格式轉化與分組和打亂
#獲取訓練特徵和訓練標籤
label = ['T (degC)','rh (%)']
x=df[future]
y=df[label]
#通過7-3劃分訓練集和測試集,70%爲訓練集 30%爲測試集
x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.3,shuffle=False,random_state=13)
#取得訓練集,和測試集的格式——》(3,6)->(1,)通過6行歷史數據7列目標特徵預測1行1列的目標
train_dataset,train_labels=multivariate_data(x_train,y_train,0,100000,3,1,1,True)
test_dataset,test_labels=multivariate_data(x_test,y_test,0,100000,3,1,1,True)
#創建訓練組,內部的batch_size,buffer_size,shuffle,batch建議百度
#該函數目標是把剛建好的訓練集/測試集轉化成tensorflow的數據集格式,打亂分組方便訓練模型......
def create_batch_dataset(x,y,train=True,buffer_size=1000,batch_size=128):
batch_data=tf.data.Dataset.from_tensor_slices((tf.constant(x),tf.constant(y)))
if train:
return batch_data.cache().shuffle(buffer_size).batch(batch_size)
else:
return batch_data.batch(batch_size)
#使用上面函數
train_batch_dataset=create_batch_dataset(train_dataset,train_labels)
test_batch_dataset=create_batch_dataset(test_dataset,test_labels,train=False)
5、模型搭建、編譯、訓練
#建立神經網絡模型-3層LSTM和一個輸出層
model= tf.keras.models.Sequential([
tf.keras.layers.LSTM(256, input_shape=train_dataset.shape[-2:],return_sequences=True), # input_shape=(20,1) 不包含批處理維度
tf.keras.layers.Dropout(0.4),
tf.keras.layers.LSTM(128, return_sequences=True),
tf.keras.layers.Dropout(0.3),
tf.keras.layers.LSTM(32),
tf.keras.layers.Dense(2)
])
#優化器和損失函數設置
model.compile(optimizer='adam',loss='mse')
#模型保存的相關設置
utils.plot_model(model)
checkpoint_file='test_model.hdf5'
checkpoint_callback=ModelCheckpoint(filepath=checkpoint_file,monitor='loss',moode='min',save_best_only=True,save_weights_only=True)
#模型訓練
history=model.fit(train_batch_dataset,epochs=30,validation_data=test_batch_dataset,callbacks=[checkpoint_callback])
通過history獲取模型每步訓練取得的結果loss和val_loss
plt.figure(figsize=(8,8),dpi=200)
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model train vs validation loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train','validation'], loc='best')
plt.show()
6、模型驗證
#通過輸入一組數據預測
test_preds=model.predict(test_dataset,verbose=1)
test_preds[:10]
# #將預測後的一組數據轉化爲1維方便比較
TEMP_preds = test_preds[:,0]
TEMP_labels = test_labels[:,0]
HUM_preds = test_preds[:,1]
HUM_labels = test_labels[:,1]
溫度預測
#r2檢驗
score=r2_score(TEMP_labels,TEMP_preds)
print(score)
0.991836296750627
#做出預測結果和實際結果的曲線對比
plt.figure(figsize=(16,8))
plt.plot(TEMP_labels,label="True value")
plt.plot(TEMP_preds,label="Pred value")
plt.legend(loc='best')
plt.show()
溼度預測
#r2檢驗
score=r2_score(HUM_labels,HUM_preds)
print(score)
0.9854786099464197
#做出預測結果和實際結果的曲線對比,使用1000次結果對比
plt.figure(figsize=(16,8))
plt.plot(HUM_labels,label="True value")
plt.plot(HUM_preds,label="Pred value")
plt.legend(loc='best')
plt.show()