TensorFlow 2.0學習筆記(4):房價預測及Overfitting處理

本文程式碼參考自:

輕鬆學會 Google TensorFlow 2.0 人工智慧深度學習實作開發書中之範例程式

購買連結

房價預測

匯入套件

import os
import numpy as np
import pandas as pd
import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow import keras
from tensorflow.keras import layers

讀取數據

data = pd.read_csv("kc_house_data.csv")# 顯示dataset的形狀,共21613比資料,每一比資料有21種不同資訊。
data.shape
# 將顯示列數設定為25,不然會有部份資料無法顯示
pd.options.display.max_columns = 25
# head 會顯示前五行的數據
data.head()

各個數據的簡寫分別代表下面意思:

  • date:房屋出售日期。
  • price:房屋價格(目標)。
  • bedrooms:臥室數量。
  • bathrooms:浴室數量。
  • sqft_living:居住的坪數(平方英尺)。
  • sqft_lot:實際的坪數(平方英尺)。
  • floors:房屋總共樓層。
  • waterfront:海景房。
  • view:房屋是否看過。
  • condition:整體條件有多好。
  • grade:房屋的整體等級(根據King County評分系統)。
  • sqft_above:除了地下室外的坪數(平方英尺)。
  • sqft_basement:地下室的坪數(平方英尺)。
  • yr_built:房屋建造時間。
  • yr_renovated:何時重新裝修過(一些沒重新裝修過或是裝修紀錄沒被記錄到的數值都為0)。
  • zipcode:郵政編碼。
  • lat:緯度座標。
  • long:經度座標。
  • sqft_living15:2015年紀錄的居住坪數(可能是翻新的原因導致sqft_living15與sqft_living不同)。
  • sqft_lot15:2015年紀錄的實際坪數(可能是翻新的原因導致sqft_lot15與sqft_lot不同)。

檢查資料型態

資料型態總共有五種:object(string),booleab, integer, float and categorical.

data.dtypes

數據前處理

轉換資料型態: 因為數據集裡的date數據是字串(string)格式,而模型的輸入只接受數值格式,所以可以透過以下程式碼將其轉為數值,並分成年、月及日三種數據。

# 將date日期拆為年、月和日並轉成數值
data['year'] = pd.to_numeric(data['date'].str.slice(0, 4))
data['month'] = pd.to_numeric(data['date'].str.slice(4, 6))
data['day'] = pd.to_numeric(data['date'].str.slice(6, 8))
## .str.slice(0,4)的method將data中原本的20141013T000000,切成2014
## .str.slice(4,6)的method將data中原本的20141013T000000,切成10
## .str.slice(6,8)的method將data中原本的20141013T000000,切成13
# 刪除沒有用的數據,inplace則是將更新後的資料存回原本的地方
data.drop(['id'], axis="columns", inplace=True)
data.drop(['date'], axis="columns", inplace=True)

分割數據集(Dataset):將數據集切割成三個部份,訓練數據(Training data)、驗證數據(Validation data)和測試數據(Testing data)。

data_num = data.shape[0]
# 取得一筆與data數量相同的亂數索引,主要目的是用於打散資料
indexes = np.random.permutation(data_num)
# 並將亂數索引值分為Train、validation和test分為,這裡的劃分比例為6:2:2
train_indexes = indexes[:int(data_num *0.6)]
val_indexes = indexes[int(data_num *0.6):int(data_num *0.8)]
test_indexes = indexes[int(data_num *0.8):]
# 透過索引值從data取出訓練資料、驗證資料和測試資料
train_data = data.loc[train_indexes]
val_data = data.loc[val_indexes]
test_data = data.loc[test_indexes]

Normalization 正規化

使用標準分數(Standard Score, 又稱z-score)將數據正規化,經過z-score正規化後數據的都會聚集在0附近, 標準差為1。

(x — 平均值) / 標準差

train_validation_data = pd.concat([train_data, val_data])
mean = train_validation_data.mean()
std = train_validation_data.std()
train_data = (train_data - mean) / std
val_data = (val_data - mean) / std

建立Numpy array格式的訓練數據

整理過後的資料共12967筆,且一筆資料有21種資訊(所以網路輸入必須為21)。

x_train = np.array(train_data.drop('price', axis='columns'))
y_train = np.array(train_data['price'])
x_val = np.array(val_data.drop('price', axis='columns'))
y_val = np.array(val_data['price'])
x_train.shape

建立並訓練網路模型

# 建立一個Sequential型態的model
model = keras.Sequential(name='model-1')
# 第1層全連接層設為64個unit,將輸入形狀設定為(21, ),而實際上我們輸入的數據形狀為(batch_size, 21)
model.add(layers.Dense(64, activation='relu', input_shape=(21,)))
# 第2層全連接層設為64個unit
model.add(layers.Dense(64, activation='relu'))
# 最後一層全連接層設為1個unit
model.add(layers.Dense(1))
# 顯示網路模型架構
model.summary()
# 設定訓練使用的優化器、損失函數和指標函數:
model.compile(keras.optimizers.Adam(0.001),
loss=keras.losses.MeanSquaredError(),
metrics=[keras.metrics.MeanAbsoluteError()])
# 創建模型儲存目錄:
model_dir = 'lab2-logs/models/'
os.makedirs(model_dir)
# 設定回調函數:# TensorBoard回調函數會幫忙紀錄訓練資訊,並存成TensorBoard的紀錄檔
log_dir = os.path.join('lab2-logs', 'model-1')
model_cbk = keras.callbacks.TensorBoard(log_dir=log_dir)
# ModelCheckpoint回調函數幫忙儲存網路模型,可以設定只儲存最好的模型,「monitor」表示被監測的數據,「mode」min則代表監測數據越小越好。
model_mckp = keras.callbacks.ModelCheckpoint(model_dir + '/Best-model-1.h5',monitor='val_mean_absolute_error',save_best_only=True,mode='min')
# 訓練網路模型:
history = model.fit(x_train, y_train, # 傳入訓練數據
batch_size=64, # 批次大小設為64
epochs=300, # 整個dataset訓練300遍
validation_data=(x_val, y_val), # 驗證數據
callbacks=[model_cbk, model_mckp])
# Tensorboard回調函數紀錄訓練過程,ModelCheckpoint回調函數儲存最好的模型

訓練結果

history.history.keys()  # 查看history儲存的資訊有哪些plt.plot(history.history['loss'], label='train')
plt.plot(history.history['val_loss'], label='validation')
plt.ylim(0.02, 0.2)
plt.title('Mean square error')
plt.ylabel('loss')
plt.xlabel('epochs')
plt.legend(loc='upper right')
plt.plot(history.history['mean_absolute_error'], label='train')
plt.plot(history.history['val_mean_absolute_error'], label='validation')
plt.ylim(0.12, 0.26)
plt.title('Mean absolute error')
plt.ylabel('metrics')
plt.xlabel('epochs')
plt.legend(loc='upper right')
# 載入模型
model = keras.models.load_model('lab2-logs/models/Best-model-1.h5')
# 先將房屋價格取出
y_test = np.array(test_data['price'])
# 標準化數據
test_data = (test_data - mean) / std
# 將輸入數據存成Numpy 格式
x_test = np.array(test_data.drop('price', axis='columns'))
# 預測測試數據
y_pred = model.predict(x_test)
# 將預測結果轉換回來(因為訓練時的訓練目標也有經過標準化)
y_pred = np.reshape(y_pred * std['price'] + mean['price'], y_test.shape)
# 計算平均的誤差百分比
percentage_error = np.mean(np.abs(y_test - y_pred)) / np.mean(y_test) * 100
# 顯示誤差百分比
print("Model_1 Percentage Error: {:.2f}%".format(percentage_error))

Overfitting處理

方法一、減少網路權重

從64改成16

model_2 = keras.Sequential(name='model-2')
model_2.add(layers.Dense(16, activation='relu', input_shape=(21,)))
model_2.add(layers.Dense(16, activation='relu'))
model_2.add(layers.Dense(1))
model_2.compile(keras.optimizers.Adam(0.001),
loss=keras.losses.MeanSquaredError(),
metrics=[keras.metrics.MeanAbsoluteError()])
log_dir = os.path.join('lab2-logs', 'model-2')
model_cbk = keras.callbacks.TensorBoard(log_dir=log_dir)
model_mckp = keras.callbacks.ModelCheckpoint(model_dir + '/Best-model-2.h5',
monitor='val_mean_absolute_error', save_best_only=True,
mode='min')
model_2.fit(x_train, y_train,
batch_size=64 ,
epochs=300,
validation_data=(x_val, y_val),
callbacks=[model_cbk, model_mckp])

方法二、加入L1或L2 正則化

model_3 = keras.Sequential(name='model-3')
model_3.add(layers.Dense(64,
kernel_regularizer=keras.regularizers.l2(0.001),
activation='relu', input_shape=(21,)))

model_3.add(layers.Dense(64, kernel_regularizer=keras.regularizers.l2(0.001), activation='relu'))
model_3.add(layers.Dense(1))
model_3.compile(keras.optimizers.Adam(0.001),
loss=keras.losses.MeanSquaredError(),
metrics=[keras.metrics.MeanAbsoluteError()])
log_dir = os.path.join('lab2-logs', 'model-3')
model_cbk = keras.callbacks.TensorBoard(log_dir=log_dir)
model_mckp = keras.callbacks.ModelCheckpoint(model_dir + '/Best-model-3.h5',
monitor='val_mean_absolute_error',
save_best_only=True,
mode='min')
model_3.fit(x_train, y_train,
batch_size=64 ,
epochs=300,
validation_data=(x_val, y_val),
callbacks=[model_cbk, model_mckp])

方法三、加入 Dropout

model_4 = keras.Sequential(name='model-4')
model_4.add(layers.Dense(64, activation='relu', input_shape=(21,)))
model_4.add(layers.Dropout(0.3))
model_4.add(layers.Dense(64, activation='relu'))
model_4.add(layers.Dropout(0.3))
model_4.add(layers.Dense(1))
model_4.compile(keras.optimizers.Adam(0.001),
loss=keras.losses.MeanSquaredError(),
metrics=[keras.metrics.MeanAbsoluteError()])
log_dir = os.path.join('lab2-logs', 'model-4')
model_cbk = keras.callbacks.TensorBoard(log_dir=log_dir)
model_mckp = keras.callbacks.ModelCheckpoint(model_dir + '/Best-model-4.h5',
monitor='val_mean_absolute_error',
save_best_only=True,
mode='min')
model_4.fit(x_train, y_train,
batch_size=64 ,
epochs=300,
validation_data=(x_val, y_val),
callbacks=[model_cbk, model_mckp])

驗證正則化的效能

model2、model3、model4

model_2 = keras.models.load_model('lab2-logs/models/Best-model-2.h5')
y_pred = model_2.predict(x_test)
y_pred = np.reshape(y_pred * std['price'] + mean['price'], y_test.shape)
percentage_error = np.mean(np.abs(y_test - y_pred)) / np.mean(y_test) * 100
print("Model_2: {:.2f}%".format(percentage_error))
model_3 = keras.models.load_model('lab2-logs/models/Best-model-3.h5')
y_pred = model_3.predict(x_test)
y_pred = np.reshape(y_pred * std['price'] + mean['price'], y_test.shape)
percentage_error = np.mean(np.abs(y_test - y_pred)) / np.mean(y_test) * 100
print("Model_3: {:.2f}%".format(percentage_error))
model_4 = keras.models.load_model('lab2-logs/models/Best-model-4.h5')
y_pred = model_4.predict(x_test)
y_pred = np.reshape(y_pred * std['price'] + mean['price'], y_test.shape)
percentage_error = np.mean(np.abs(y_test - y_pred)) / np.mean(y_test) * 100
print("Model_4: {:.2f}%".format(percentage_error))

Written by

Machine Learning / Deep Learning / Python / Flutter cakeresume.com/yanwei-liu

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store