Kaggle入門級賽題:房價預測——數據挖掘篇

特徵工程

咱們注意到 MSSubClass 實際上是一個 category 的值:算法

all_df['MSSubClass'].dtypes

有:app

dtype('int64')

它不該該作爲數值型的值進行統計。所以,進行強制類型轉換,把它變回 string學習

df['MSSubClass'] =df['MSSubClass'].astype(str)

而後,統計其出現頻次:測試

all_df['MSSubClass'].value_counts()

clipboard.png

就很清楚的瞭解 MSSubClass 特徵了。spa

當咱們用 numerical 來表達 categorical 的時候要注意,數字自己有大小的含義,因此亂用數字會給以後的模型學習帶來麻煩。這裏咱們能夠用 One-Hot 的方法來表達 categorycode

pandas 自帶的get_dummies方法,能夠作到一鍵 One-Hotip

pd.get_dummies(df['MSSubClass'], prefix='MSSubClass').head()

效果以下:
clipboard.pngget

此時,MSSubClass 被咱們分紅了 12 列,每列表明一個 category,是爲 1,否爲 0。string

因此,同理。接下來,咱們須要把全部的 category 數據所有一鍵 One-Hotpandas

all_dummy_df = pd.get_dummies(df)
all_dummy_df.head()

此時,數據長這樣子:

clipboard.png

接下來,咱們來處理 numerical 的數據。

首先查看 One-Hot 後的缺失值:

all_dummy_df.isnull().sum().sort_values(ascending=False).head(10)

clipboard.png

咱們須要對這些缺失值進行處理,這裏採用平均值來填充空缺:

mean_cols = all_dummy_df.mean()
all_dummy_df = all_dummy_df.fillna(mean_cols)

再次查看是否有缺失值:

all_dummy_df.isnull().sum().sum()

顯示爲 0,即缺失值都已被填充。

到這裏,咱們通過以上步驟處理過的數據,就能夠餵給分類器進行訓練了。爲了讓數據更加規整化,數據間的差距不要太大,在一個標準分佈內,也就是數據平滑化。咱們對那些原本就是 numerical 的數據進行處理(與 One-Hot 的 0/1 數據不一樣)。

首先,咱們來查看哪些是 numerical 的數據:

numeric_cols = df.columns[df.dtypes != 'object']
numeric_cols

clipboard.png

採用公式(X-X')/s,計算標準分佈:

numeric_col_means = all_dummy_df.loc[:, numeric_cols].mean()
numeric_col_std = all_dummy_df.loc[:, numeric_cols].std()
all_dummy_df.loc[:, numeric_cols] = (all_dummy_df.loc[:, numeric_cols] - numeric_col_means) / numeric_col_std

獲得的數據以下:

all_dummy_df.head()

clipboard.png

以上就完成了對數據的處理。

創建模型

首先,把數據集分回訓練集和測試集:

dummy_train_df = all_dummy_df.loc[train_df.index]
dummy_test_df = all_dummy_df.loc[test_df.index]

首先採用 Ridge Regression 模型,由於對於多因子的數據集,這種模型能夠方便的把全部的變量都一股腦的放進去,咱們先用這種模型作實驗。

爲了更好的使用 Sklearn,我在這裏把 DataFrame 轉化成 Numpy Array(這一步不是必須):

X_train = dummy_train_df.values
X_test = dummy_test_df.values

把數據放到模型裏跑一遍,用 Sklearn 自帶的 cross validation 方法來測試模型:

from sklearn.linear_model import Ridge
from sklearn.model_selection import cross_val_score

alphas = np.logspace(-3, 2, 50)
test_scores=[]
for alpha in alphas:
    clf = Ridge(alpha)
    test_score = np.sqrt(-cross_val_score(clf, X_train, y_train, cv=10, scoring='neg_mean_squared_error'))
    test_scores.append(np.mean(test_score))

存下全部的 CV 值,看看哪一個 alpha 值更好,也就是咱們常說的調參數

plt.plot(alphas, test_scores)
plt.title("Alpha vs CV Error")
plt.xlabel("alpha")
plt.ylabel("CV Error")

clipboard.png

能夠看到,當 alpha 爲 10 到 20 的時候,CV Error 達到最低 0.135 左右。也就是說大約 alpha = 15 的時候給了咱們最好的結果。

通常來講,單個分類器的效果有限。咱們會傾向於把多個分類器合在一塊兒,作一個「綜合分類器」以達到最好的效果。因此接下來咱們要作的事就是 ensemble

Ensemble 的方法有 BaggingBoosting 兩大類。Bagging 把不少的小分類器放在一塊兒,每一個訓練隨機的一部分數據,而後採用多數投票制把它們的最終結果綜合起來。Boosting 比 Bagging 理論上更高級點,它也是攬來一把的分類器。可是把他們線性排列。下一個分類器把上一個分類器分類得很差的地方加上更高的權重,這樣下一個分類器就能在這個部分學得更加「深入」。下面咱們分別來看一下。

Bagging

from sklearn.ensemble import BaggingRegressor
from sklearn.model_selection import cross_val_score

params = [1, 10, 15, 20, 25, 30, 40]
test_scores = []
for param in params:
    clf = BaggingRegressor(n_estimators=param, base_estimator=ridge)
    test_score = np.sqrt(-cross_val_score(clf, X_train, y_train, cv=10, scoring='neg_mean_squared_error'))
    test_scores.append(np.mean(test_score))
    
plt.plot(params, test_scores)
plt.title("n_estimator vs CV Error")

clipboard.png

能夠看到,咱們用 15 個小的 ridge 分類器就達到了 0.134 如下的效果。

Boosting

from sklearn.ensemble import AdaBoostRegressor

params = [10, 15, 20, 25, 30, 35, 40, 45, 50]
test_scores = []
for param in params:
    clf = BaggingRegressor(n_estimators=param, base_estimator=ridge)
    test_score = np.sqrt(-cross_val_score(clf, X_train, y_train, cv=10, scoring='neg_mean_squared_error'))
    test_scores.append(np.mean(test_score))
    
plt.plot(params, test_scores)
plt.title("n_estimator vs CV Error");

clipboard.png

20 個小的 ridge 分類器的效果,達到了 0.133。

最後,祭出 xgboost 大殺器:

from xgboost import XGBRegressor

params = [1,2,3,4,5,6]
test_scores = []
for param in params:
    clf = XGBRegressor(max_depth=param)
    test_score = np.sqrt(-cross_val_score(clf, X_train, y_train, cv=10, scoring='neg_mean_squared_error'))
    test_scores.append(np.mean(test_score))

plt.plot(params, test_scores)
plt.title("max_depth vs CV Error")

clipboard.png

咱們看到,當參數爲 5 的時候,效果接近 0.125!

提交結果

最後,咱們將訓練好的模型對數據進行訓練:

xgb = XGBRegressor(max_depth=5)
xgb.fit(X_train, y_train)
y_xgb = np.expm1(xgb.predict(X_test))
submission_df = pd.DataFrame(data= {'Id' : test_df.index, 'SalePrice': y_xgb})

最終,咱們輸出的數據長這樣子:

submission_df.head()

clipboard.png

將它存爲.csv文件:

submission_df.to_csv('submission_xgb.csv',index=False)

提交到 kaggle 平臺的 Score 是 0.13942,排名在 50% 左右。整個過程沒有對特徵信息進行太多的處理,還有太多須要改進的地方。

後記

第一次完完整整的從頭至尾本身作了一個比賽,仍是有太多地方淺淺略過,確實,若是隻是調參跑模型的話,應該不是難事,可是如何得到更好的效果,數據量大時現有的程序跑不動,須要改進算法等方面,還有太多值得學習的地方,由於這件事好像沒有一個最優結果,只有更優的結果。


不足之處,歡迎指正。

相關文章
相關標籤/搜索