Boston House Price Prediction-zero to hero

/

專案介紹

這是 Kaggle 的入門專案,也是練習迴歸問題很好的專案,下面我將帶領大家透過這個專案學習數據分析的方法,從數據清洗一直到選擇最佳模型,並做出最後預測,相信大家看完整個流程後對數據分析有較為全面的理解,同時,也希望大家能動手實作,這樣對問題才會有更深入的理解,廢話不多說,開始進入主題吧!
這個專案可分為下列幾個步驟,我將一步一步教大家如何運用 Python 的 libaries 完成這些步驟。

1.導入模塊、導入資料

#導入模塊
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import xgboost as xgb
from sklearn.model_selection import GridSearchCV, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import Ridge
from sklearn.svm import SVR
from sklearn.ensemble import RandomForestRegressor

# 導入資料
data_train = pd.read_csv("../input/house-prices-advanced-regression-techniques/train.csv")
data_test = pd.read_csv("../input/house-prices-advanced-regression-techniques/test.csv")
data_all = pd.concat([data_train, data_test], axis = 0)

print(data_test.shape)
data_all.head()

2.查看資料特徵

# 查看特徵數據型態、特徵缺失值數目

data_all.info()

"training data shape:{}, testing data shape:{}".format(data_train.shape,data_test.shape)

3.篩選重要特徵

我將使用 correlation matrix 對數值特徵進行篩選,correlation matrix 的每個元素代表不同特徵間的關聯度,數值越高,關聯度越高,因為我們要對房價進行預測,因此,我將選出與 SalePrice 關聯度最高的 19 個特徵放入模型中,另外,我會將缺失值超過一半的類別特徵從資料中移除。

# 根據特徵間的 correlation 畫出 heatmap 

f, ax = plt.subplots(figsize=(20, 9))
sns.heatmap(data_train.corr(), vmax=0.8, square=True)

# 選出與 SalePrice 關聯度最高的 num_var 個 "數值特徵"

num_var = 19
value_cols = list(data_train.corr().nlargest(num_var + 1, "SalePrice")["SalePrice"].index)
value_cols.remove('SalePrice')

value_cols

# 搜集所有類別特徵

categorical_cols = []
for col in data_all.columns: 
    if str(data_all[col].dtype) == "object": 
        categorical_cols.append(col)

# 查看類別特徵缺失值數目
# 移除缺失值超過一半的類別特徵 

miss_value_count = data_train[categorical_cols].isnull().sum()

for index in miss_value_count.index:
    if miss_value_count[index] >730: 
        categorical_cols.remove(index)

data_train[categorical_cols].isnull().sum()

# 人工選取類別特徵

categorical_cols = ['MSZoning','Street','Neighborhood','ExterQual','BsmtQual','Heating','CentralAir','Electrical',
  'KitchenQual','GarageQual','SaleCondition']
  ```
  # 4. 填補缺失值
  數值特徵使用平均值填補缺失值,類別特徵使用 test set 上眾數填補。需要注意當我們在填補數值特徵的缺失值時使用 training set 上的平均值對 training set & test set 同時填補缺失值,而不能使用 training set & test set 做出來的平均填補缺失值,這樣有作弊的嫌疑喔 !
  ```python
  # 查看缺失值
data_all[value_cols + categorical_cols].info()

# 數值特徵用平均值填補缺失值
# 類別特徵用眾數填補缺失值

for col in ['GarageCars', 'GarageArea', 'TotalBsmtSF', 'GarageYrBlt', 'MasVnrArea', 'BsmtFinSF1', 'LotFrontage']: 
    data_all[col].fillna(data_train[col].sum()/1460, inplace=True)

for col in ['MSZoning', 'BsmtQual', 'Electrical', 'KitchenQual', 'GarageQual']:
    data_all[col].fillna(data_train[col].mode()[0], inplace=True)

5. 類別特徵 One Hot Encode 轉換

當我們把資料放到模型訓練時,機器看不懂類別型態的資料,因此,我們要將類別類型的特徵轉換為數值類型的資料,常見的轉換方式有 Label Encode 與 One Hot Encode 兩種方法。One Hot Encode 會將特徵轉換為向量形式,舉例來說,如果某個特徵有三個類別:$A, B, C$,One Hot Encode 會將 $A, B, C$ 類別分別以向量 $[0,0], [1,0], [0,1]$ 表示,而 Label Encode 會將 $A, B, C$ 類別分別以 $0, 1, 2$ 表示,但 Label Encode 轉換後隱含了類別間存在順序關係,因此,不適用於類別間無順序關係的情況,這邊我將選取的類別特徵都轉換為 One Hot Encode 型式。與缺失值填補邏輯一樣,我們將對 training set & test set 同時進行 One Hot Encode 以保證轉換後的一致性。

# 對類別特徵進行 onehot encode
# 注意: 需要對 training set, test set 同時操作

data_all = pd.concat([pd.get_dummies(data_all[categorical_cols], drop_first = True), data_all[value_cols]], axis=1)
data_all

6.資料標準化

最後,要將資料進行標準化,標準化的公式如下:
$$
X \rightarrow \frac{X-\mu}{\sigma}
$$
其中,$\mu, \sigma$ 分別為特徵的平均值與變異數,標準化的目的在使不同特徵尺度一致,如此一來,機器在學習的過程中不會傾向任何一個尺度較大的特徵,同時,它也可以加快機器在梯度下降時的收斂速度。另外,也要注意在 training set & test set 上做標準化所使用的平均值與變異數皆為 training set 上計算而得的,這裡不再贅述。

# 打亂資料順序,以免之後影響模型的學習
shuffle_index = list(range(1460))
np.random.shuffle(shuffle_index)

X_train = data_all[:1460].loc[shuffle_index,:]
y_train = data_train["SalePrice"][shuffle_index]
X_test = data_all[1460:]

scaler = StandardScaler()

# 計算 X_train 的平均值與變異數
scaler.fit(X_train)    

# 標準化 X_train, X_test => X_train_scale, X_test_scale
X_train_scale = scaler.transform(X_train)   
X_test_scale = scaler.transform(X_test)

print("X_train shape:", X_train.shape)
print("X_test shape:", X_test.shape)
print("y_train shape:", y_train.shape)
print("X_train_scale shape:", X_train_scale.shape)
print("X_test_scale shape:", X_test_scale.shape)

7. 超參數選擇與模型選擇

我們已經完成了資料清洗與特徵工程,接下來會將資料放入不同模型進行訓練,並找出最佳模型,我將它分為以下兩個步驟:

  1. 對下面四個模型進行超參數選擇(hyperparameter Tuning),分別選出每個模型的最佳參數。
    • Ridge
    • RandomForestRegressor
    • XGBRegressor
    • SVC
  2. 比較以上模型的 mean squared error,選出最佳模型。
#建立 regs 字典存取四個模型的最佳參數
regs = {}
#建立 scores 字典存取四個模型的最佳 score
scores = {}
#使用 GridSearchCV 函數找出 Ridge 最佳參數 
param_grid = {'alpha': [0.1, 0.5, 1, 5, 10, 50, 100]}
reg = GridSearchCV(Ridge(), param_grid, scoring="neg_mean_squared_error", cv=3)
reg.fit(X_train_scale, y_train)

#存取最佳參數
regs["Ridge"] = reg
scores["Ridge"] = reg.best_score_
print("best estimator: {}".format(reg.best_params_))

#建立 regs 字典存取四個模型的最佳參數
regs = {}

#建立 scores 字典存取四個模型的最佳 score
scores = {}
#使用 GridSearchCV 函數找出 Ridge 最佳參數 
param_grid = {'alpha': [0.1, 0.5, 1, 5, 10, 50, 100]}
reg = GridSearchCV(Ridge(), param_grid, scoring="neg_mean_squared_error", cv=3)
reg.fit(X_train_scale, y_train)

#存取最佳參數
regs["Ridge"] = reg
scores["Ridge"] = reg.best_score_
print("best estimator: {}".format(reg.best_params_))

#找出 XGBRegressor 最佳參數 
param_grid = {'n_estimators': [5000, 10000], 'max_depth': [2,3], 'learning_rate': [0.01, 0.05]}
reg = GridSearchCV(xgb.XGBRegressor(), param_grid, scoring="neg_mean_squared_error", cv=3)
reg.fit(X_train, y_train)

#存取最佳參數
regs["XGBRegressor"] = reg
scores["XGBRegressor"] = reg.best_score_
print("best estimator: {}".format(reg.best_params_))

#找出 SVR 最佳參數 
param_grid = {'C': [0.1, 0.5, 1, 5, 10, 20, 30, 40, 50, 100, 300, 400, 500, 1000]}
reg = GridSearchCV(SVR(), param_grid, scoring="neg_mean_squared_error", cv=3)
reg.fit(X_train_scale, y_train)

#存取最佳參數
regs["SVR"] = reg
scores["SVR"] = reg.best_score_
print("best estimator: {}".format(reg.best_params_))

#找出四個模型中最好的模型
final_regressor = max(scores, key=scores.get)
final_regressor

#對最佳模型進行訓練,並進行預測
final_result = regs[final_regressor].predict(X_test)

#將結果存為 csv 檔 
#提交結果 0.13796
col1 = data_test["Id"]
col2 = pd.DataFrame(final_result, columns =["SalePrice"])
output = pd.concat([col1,col2], axis=1)
output.to_csv("./house_prices_submission_xgb.csv", index=False)

發佈留言

This site uses Akismet to reduce spam. Learn how your comment data is processed.