Kaggle 入門並實戰房價預測

Max_Lyu發表於2019-05-25

 

  今天看了個新聞,說是中國社會科學院城市發展與環境研究所及社會科學文獻出版社共同釋出《房地產藍皮書:中國房地產發展報告No.16(2019)》指出房價上漲7.6%,看得我都坐不住了,這房價上漲什麼時候是個頭啊。為了讓自己以後租得起房,我還是好好努力吧。於是我開啟了Kaggle,準備上手第一道題,正巧發現有個房價預測,可能這是命運的安排吧......

一、下載資料

  進入到 kaggle 後要先登入,需要注意的是,註冊的時候有一個驗證,要FQ才會顯示驗證資訊。

      

  

  下載好資料之後,大致看一下資料的情況,在對應題目的頁面也有關於資料屬性的一些解釋,看一下對應資料代表什麼。

二、資料預處理

 提取 y_train 並做相應處理

  先匯入需要用到的包,通過 pandas 的 read_csv(filename, index_col=0) 分別將測試集和訓練集匯入。完了之後,我們把訓練集裡的“SalePrice”取出來,檢視它的分佈情況並作一下處理。

y_train = train_data.pop('SalePrice')
y_train.hist()

            

  由此可見資料並不平滑,因此需要將其正態化,正態化可以使資料變得平滑,目的是穩定方差,直線化,使資料分佈正態或者接近正態。正態化可以用 numpy 的 log1p() 處理。log1p(y_train) 可以理解為 log 1 plus,即 log(y_train + 1)。正態化之前,先看一下如果正態化之後的價格分佈。

      

  這樣的分佈就很好了,因此我們通過 numpy 的 log1p() 將 y_train 正態化。

y_train = np.log1p(y_train)

 將去掉 SalePrice 的訓練集和測試集合並

  為了將兩個資料集一起處理,減少重複的步驟,將兩個資料集合並再處理。使用 pandas 的 concat() 將訓練集和測試集合並起來並看一下合併後的資料的行數和列數,以確保正確合併。

data = pd.concat((train_data, test_data), axis=0)
data.shape

 特徵處理

  資料集中有幾個跟年份有關的屬性,分別是:

  • YrSold: 售出房子的年份;
  • YearBuilt:房子建成的年份;
  • YearRemodAdd:裝修的年份;
  • GarageYrBlt:車庫建成的年份

  算出跟售出房子的時間差,並新生成單獨的列,然後刪除這些年份

data.eval('Built2Sold = YrSold-YearBuilt', inplace=True)
data.eval('Add2Sold = YrSold-YearRemodAdd', inplace=True)
data.eval('GarageBlt = YrSold-GarageYrBlt', inplace=True)
data.drop(['YrSold', 'YearBuilt', 'YearRemodAdd', 'GarageYrBlt'], axis=1, inplace=True)

  接下來進行變數轉換,由於有一些列是類別型的,但由於pandas的特性,數字符號會被預設成數字。比如下面三列,是以數字來表示等級的,但被認為是數字,這樣就會使得預測受到影響。

  • OverallQual: Rates the overall material and finish of the house
  • OverallCond: Rates the overall condition of the house
  • MSSubClass: The building class

  這三個相當於是等級和類別,只不過是用數字來當等級的高低而已。因此我們要把這些轉換成 string

data['OverallQual'] = data['OverallQual'].astype(str)
data['OverallCond'] = data['OverallCond'].astype(str)
data['MSSubClass'] = data['MSSubClass'].astype(str)

 把category的變數轉變成numerical 

  我們可以用One-Hot的方法來表達category。pandas自帶的get_dummies方法,可以一鍵做到One-Hot。

  這裡按我的理解解釋一下One-Hot:比如說有一組自擬的資料 data,其中 data['學歷要求']有'大專', '本科', '碩士', '不限'。但data['學歷要求']=='本科',則他可以用字典表示成這樣{'大專': 0, '本科':1, '碩士':0, '不限':0},用向量表示為[0, 1, 0, 0]

dummied_data = pd.get_dummies(data)

      

 處理numerical變數

  category變數處理好了之後,就該輪到numerical變數了。檢視一下缺失值情況。

dummied_data.isnull().sum().sort_values(ascending=False).head()

           

  上面的資料顯示的是每列對應的缺失值情況,對於缺失值,需要進行填充,可以使用平均值進行填充。

mean_cols = dummied_data.mean()
dummied_data = dummied_data.fillna(mean_cols)

 標準差標準化

  缺失值處理完畢,由於有一些資料的值比較大,特別是比起 one-hot 後的數值 0 和 1,那些幾千的值就相對比較大了。因此對數值型變數進行標準化。

numerical_cols = data.columns[data.dtypes != 'object']  # 資料為數值型的列名
num_cols_mean = dummied_data.loc[:, numerical_cols].mean()
num_cols_std = dummied_data.loc[:, numerical_cols].std()
dummied_data.loc[:, numerical_cols] = (dummied_data.loc[:, numerical_cols] - num_cols_mean) / num_cols_std

  到這裡,資料處理算是完畢了。雖然這樣處理還不夠完善,後面如果技術再精進一點可能會重新弄一下。接下來需要將資料集分開,分成訓練集合測試集。

X_train = dummied_data.loc[train_data.index].values
X_test = dummied_data.loc[test_data.index].values

三、建模預測

  由於這是一個迴歸問題,我用 sklearn.selection 的 cross_val_score 試了嶺迴歸(Ridge Regression)、BaggingRegressor 以及 XGBoost。且不說整合演算法比單個迴歸模型好,XGBoost  不愧是 Kaggle 神器,效果比 BaggingRegressor 還要好很多。安裝 XGBoost  的過程就不說了,安裝好之後匯入包就行了,但是我們還要調一下參。

params = [6,7,8]
scores = []
for param in params:
    model = XGBRegressor(max_depth=param)
    score = np.sqrt(-cross_val_score(model, X_train, y_train, cv=10, scoring='neg_mean_squared_error'))
    scores.append(np.mean(score))
plt.plot(params, scores)

          

  可見當 max_depth = 7 的時候,錯誤率最低。接下來就是建模訓練預測了。

xgbr = XGBRegressor(max_depth=7)
xgbr.fit(X_train, y_train)
y_prediction = np.expm1(xgbr.predict(X_test))

  得到結果之後,將結果儲存為 .csv 檔案,因為 kaggle 的提交要求是 csv 檔案,可以到 kaggle 看一下提交要求,前面下載的檔案裡面也有一份提交樣式,照它的格式儲存檔案就好了。

submitted_data = pd.DataFrame(data= {'Id' : test_data.index, 'SalePrice': y_prediction})
submitted_data.to_csv('./input/submission.csv', index=False)  # 將預測結果儲存到檔案

 四、提交結果

      

       

  提交的時候也要FQ,才會上傳檔案。到這裡就結束了。

 

  想要第一時間獲取更多有意思的推文,可關注公眾號: Max的日常操作

                            

 

相關文章