kaggle實戰-房價預測

繼續上次的話題,這回將完成從數據處理開始到最後的提交的整個流程。讓我們看看只用簡單的線性模型,能取得多好的效果。

第一步:導入必要的庫:這裡我們導入常用的pandas,seaborn,numpy,matplotlib等

import pandas as pdimport seaborn as snsimport matplotlibimport numpy as npimport matplotlib.pyplot as pltfrom scipy.stats import skew%matplotlib inline%config InlineBackend.figure_format = retina

讀取數據:

train = pd.read_csv("data/train.csv")test = pd.read_csv("data/test.csv")

我們來看下train的頭五行

train.head()

可以看到我們的數據有81行,除去第一行Id和最後一行的SalePrice,我們首先提取train和test共有的79個特徵

all_data = pd.concat([train.loc[:,"MSSubClass":"SaleCondition"], test.loc[:,"MSSubClass":"SaleCondition"]])

1.這裡用loc是因為DataFrame結構的數據由loc按index索引,由iloc按下標索引。如果在裡面寫上axis=1,則表示train和test數據按橫排鏈接,不符合我們的要求

2.看下all_data

all_data.shape

(2919, 79)

接下來我們對數據進行預處理,預處理的工作主要是:

1.針對偏度比較大的數據用log1p函數進行轉化使其更加服從高斯分布

2.離散型數據轉化為數值型數據

3.對缺失的數據項用均值填充

4.提取出X_train,X_test,y

首先看下SalePrice進行log1p處理之後的對比圖

prices = pd.DataFrame({"Prices":train.SalePrice,"Log1p(prices)":np.log1p(train.SalePrice)})matplotlib.rcParams["figure.figsize"] = (12.0, 8.0)prices.hist()

可以明顯看出來進行了log1p操作後,整體分布更符合高斯分布,這是符合我們的預期的

接下來我們對偏度大於0.75的數值特徵進行同樣的操作使其趨向符合高斯分布

numeric_feats = all_data.dtypes[all_data.dtypes!=object].index #numeric_feats 數值特徵skwed_feats = all_data[numeric_feats].apply(lambda x: skew(x.dropna()))#skwed_feats 偏度特徵skwed_feats = skwed_feats[skwed_feats>0.75].index# 選取大於0.75的,別忘了取索引all_data = pd.get_dummies(data=all_data,dummy_na=True)# get_dummies轉化離散標籤為數值標籤,別忘了左邊添加all_dataall_data = all_data.fillna(all_data.mean())# 這一步對all_data的缺失項填補mean值以避免下一步log1p報錯(NAN)all_data[skwed_feats] = np.log1p(all_data[skwed_feats])# log1p處理,注意:開始我等式左邊寫成了all_data,導致all_data的數據長度變成了(2919,22)X_train = all_data[:train.shape[0]]X_train.shapeX_test = all_data[train.shape[0]:]y = train.SalePrice

模型:

1.導入所需的庫

2.定義損失函數rmse_cv(model)

3.畫出相關性矩陣圖

from sklearn.linear_model import Ridge, RidgeCV, ElasticNet,LassoCV, LassoLarsCVfrom sklearn.model_selection import cross_val_scoredef rmse_cv(model): rmse = np.sqrt(-cross_val_score(model, cv=5, scoring="neg_mean_squared_error",X=X_train,y=y)) return(rmse)model_ridge = Ridge()alphas = [0.05, 0.1, 0.3, 1, 3, 5,10, 15, 30, 50, 75]cv_Ridge = [rmse(Ridge(alpha)).mean() for alpha in alphas]cv_Ridge = pd.Series(cv_Ridge, index=alphas)cv_Ridge.plot(title="Validation-Just Do It.")plt.xlabel="Alphas"plt.ylabel="rmse"

我們明顯可以看到在alpha為10時我們取得最小的誤差

cv_Ridge.min()

0.12733734668670776

model_lasso = LassoCV(alphas=[1, 0.1, 0.001, 0.0005]).fit(X_train, y)rmse(model_lasso).mean()

0.12314421090977427

coef = pd.Series(model_lasso.coef_, index=X_train.columns)

記錄相關性矩陣coef

print("Lasso picked"+ str(sum(coef != 0)) + " valveables and eliminated " + str(sum(coef == 0)) + " valueables.")

Lasso picked 110 valveables and eliminated 178 valueables.

imp_coef = pd.concat([coef.sort_values().head(10), coef.sort_values().tail(10)])matplotlib.rcParams["figure.figsize"]=(10.0, 10.0)imp_coef.plot(kind="barh")imp_coef.plot(title="Coffecients in the Lasso Model.")

可以看出相關性最大和最小的各10個特徵

matplotlib.rcParams["figure.figsize"] = (6, 6)preds = pd.DataFrame({"preds":model_lasso.predict(X_train), "true":y})preds["residuals"] = preds["true"] - preds["preds"]preds.plot(x="preds", y="residuals",kind="scatter")

上面我們畫出了預測值與殘差值的散點圖關係,可以看出效果應該還可以,讓我們來在kaggle上提交試試吧!

提交前的最後一個工作,因為我們之前已經進行過log1p的工作,所以預測出來的值需要還原,也就是exp(x)-1,其實還有另一個簡單的函數可以調用也就是np.expm1(x),這個函數在後面我們會用到

from math import exppreds_test = pd.DataFrame({"Id":test["Id"], "SalePrice":list(exp(x)-1 for x in model_lasso.predict(X_test))})preds_test.to_csv(submisson.csv, index=False)

可以看到,我們已經得到了submisson.csv的文件

提交的最後成績:

這個成績大概是排在總共3000多支隊伍的前26%的樣子。

進一步優化:引入XGBoost

import xgboost as xgbdtrain = xgb.DMatrix(X_train, label=y)dtest = xgb.DMatrix(X_test)params = {"max_depth":2, "eta":0.1}model = xgb.cv(params, dtrain, num_boost_round=500, early_stopping_rounds=100)model.tail()

可以看到我們的模型有四個屬性,分別是測試集和訓練集上的誤差均值和誤差方差,我們取兩個均值來看看曲線圖

model.loc[30:,["test-rmse-mean", "train-rmse-mean"]].plot()

model_xgb = xgb.XGBRegressor(learning_rate=0.1,max_depth=2,n_estimators=360)model_xgb.fit(X_train,y)xgb_preds = np.expm1(model_xgb.predict(X_test))lasso_preds = np.expm1(model_lasso.predict(X_test))predictions = pd.DataFrame({"xgb_preds":xgb_preds,"lasso_preds":lasso_preds})predictions.plot(x="xgb_preds", y="lasso_preds",kind="scatter")

可以看到呢,lasso_preds也就是一階的模型和xgb模型幾乎是成正比相關的,一般來說,啷個不相關的(或者說相關係數低)模型進行混合會有顯著的提升,所以在這種情況下對我們模型預測效果的提升強度應該不大。我們來驗證下。

同樣的,生成預測集的label。

preds = 0.5*lasso_preds+0.5*xgb_preds # 混合模型solution = pd.DataFrame({"Id":test.Id, "SalePrice":preds})solution.to_csv("ridge_sol.csv",index=False)

提交生成的ridge_sol.csv:

Anyway,我們得到了0.0001的提升,em....不論如何最終這次提交的排名定格在前25%。還有很大的提升空間!

感謝閱讀

Ref:

Regularized Linear Models | Kaggle?

www.kaggle.com

Comprehensive data exploration with Python?

www.kaggle.com


推薦閱讀:

kaggle小黃車競賽 得分:0.41038
用126郵箱註冊了Kaggle,但是無法驗證,提示未輸入正確驗證碼,這是為何呢?
[TED] 聽Kaggle創始人講講這些年會被機器"搶"走的工作
清華兩名博士從1萬名數據科學家中脫穎而出,獲得癌症檢測演算法頭名 ‖ 附冠軍團隊代碼
用TensorFlow做Kaggle「手寫識別」達到98%準確率-詳解

TAG:機器學習 | Kaggle |