2、房價預測實戰中學到的經驗

weixin_34249678發表於2016-11-18

用Bagging優化模型的過程:
1、對於要使用的弱模型(比如線性分類器、嶺迴歸),通過交叉驗證的方式找到弱模型本身的最好超引數;
2、然後用這個帶著最好超引數的弱模型去構建強模型;
3、對強模型也是通過交叉驗證的方式找到強模型的最好超引數(比如弱模型的數量)

對於Bagging、RandomForest、Boosting這些組合演算法,預設是用的弱模型是決策樹,但是可以通過base_estimator引數調整。

1、檢視資料,資料預處理

讀入資料

train_df = pd.read_csv(filename,index_col=0)

dataframe.head()

觀察資料分佈

對於連續型數值變數,檢視的是直方圖。
對於分型別變數,檢視的是頻數圖。其實和直方圖差不多。

首先,檢視因變數(y,房價)的分佈,看原始分佈的時候,還做了個轉換,對房價取了個對數。同時檢視兩狀態下的資料分佈。

之所以看分佈和做轉換,是因為用線性迴歸有個條件是因變數符合正態分佈,如果不是的話,最好做個平滑處理,讓其儘可能符合高斯分佈,否則效果不會好。

%matplotlib inline
pricesDf = pd.DataFrame( {"price":df['salePrice'] ,"log_price+1":np.log1p(df['salePrice']) })
這行程式碼其實是用原始資料中的房價和取對數後的房價建立了個新的DataFrame

log1p就是 log(x+1),可以避免出現負數結果,逼格很高。
不過,如果用平滑後的價格做模型,那麼做預測時,預測結果也不要忘記反向操作,反向函式就是expm1,log反向是exp
priceDf.hist()
然後用柱狀圖繪製分佈

測試資料和訓練資料合併

合併的目的是後續的特徵處理時,就一併把訓練集和測試集的一併轉換了。
當然,最後訓練的時候還是要用訓練資料集,驗證時還是要用測試資料集。我們就直接用train_df.index和test_df.index把它們再提取出來就好了。

all_df = pd.concat((train_df,test_df), axis=0)

2、特徵工程

把分型別變數數字化

當用數值型變數表達分類變數時,由於數字本身有大小的含義,所以亂給數字會給後來的模型學習帶來麻煩,所以對於分型別變數,更好的方法是one-hot編碼。

pandas方法
all_df['columnname'].value_count()
pd.get_dummies(all_df ['columnname'] , prefix='SomePrefix' ).head()

得到的one-hot column的名字是'SomePrefix_value'的樣式

也可以一次性對所有分類變數one-hot

all_dummy_df = all_df.get_dummies(all_df)
all_dummy_df.head()

對數值變數的處理

首當其衝就是對缺失值的處理。

缺失值的處理

檢視缺失值最多的列

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

對於缺失值的處理,需要根據具體的情況作處理。

比如,用均值填充

mean_cols=all_dummy_df.mean()
mean_cols.head(10)
用均值填充
all_dummy_df.fillna(mean_cols,inplace=True) 就地填充

資料分佈標準化處理

並不是所有的模型都需要做資料分佈的標準化處理,但是像迴歸模型比較嬌貴,最好把自變數放在一個標準正態分佈裡,不要讓資料的差距太大。
當然對於哪些one-hot的列,因為只有0,1兩個值,所以不需要標準化,我們的目標應該只是那些本來就是數值型變數。

先看哪些列是數值型的
numeric_cols = all_df.columns[add_df.dtypes != 'object']
這些列就是數值型列的索引
計算標準分佈: (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] - umeric_col_means) / numeric_col_std

3、建立模型

資料集分成訓練/測試集

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

把pandas的DataFrame轉換成numpy的Array,只是為了和sklearn更配

x_train = train_df.values
x_test=test_df.values

剩下就是用sklearn的嶺迴歸Ridge訓練模型了,這個模型需要一個alpha超參,我們用交叉驗證得到最優的引數值。

交叉驗證的程式碼套路是固定的:

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

這段程式碼執行完畢後,我們有兩個列表,一個是alphas列表,一個是test_scores列表。用這兩個列表畫一個折線圖,我們就可以觀察到在alpha取什麼值的時候,誤差最小。

同樣的資料集,也可以用RandomForestRegressor來做迴歸。這個模型有兩個超引數,最大特徵個數、最大采樣數量。

max_features=[.1 ,.3 ,.5 ,.7 ,.9 ,.99]
test_scores=[]
for max_feat in max_features:
clf = RandomForestRegressor(n_estimators=200,max_features=max_feat)
#n_estimators 代表要多少棵樹
test_scores=np.sqrt(-cross_val_score(clf,X_train,y_train,cv=5,scoring='neg_mean_squared_error')
test_scores.append(np.mean(test_scores))

通過交叉驗證,我們可以找到兩個模型的最佳超引數。

4、模型融合

簡單的我們可以用bagging的方法,把兩個模型最好測引數拿出來,組合成最終的model。每個模型都做個預測值,最終兩個模型的預測值取平均。

5、提交結果

走你~

6、進階優化 用高階的模型融合

一般來說,單個分類器的效果有效,我們會傾向於把N多的分類器合在一起,做一個綜合分類器達到最好的效果。

sklearn中已經有現成框架,在sklearn.ensemble中,有bagging有Boosting。Bagging和Bossting又都有迴歸和分類之分。把bagging用在迴歸上,也是同時得到多個迴歸模型,比如這個案例中我們用Ridge做迴歸器,最後就是得到多個Ridge。

Bagging預設的用的是DecisionTree,通過改變base_estimator引數的值就可以修改弱模型的型別了。

from sklearn.ensemble import BaggingRegressor

之前,我們通過交叉驗證的方法,得到了Ridge嶺迴歸alpha引數的最佳值。
我們就可以用這個最佳引數作為小分類器。

from sklearn.linear_model import Ridge
ridge = Ridge(alpha=15)

而我們在接下來是用Bagging時,同樣是要用交叉驗證,訓練出來的其實是小分類器的個數的最佳值。

我們先定義小分類器的個數

params = [1,10,15,20,25,30,40]
....
找到最佳的小回歸器的數量。

大殺器,xgboost

可以用xgboost,而且xgboost可以用一樣的模式嵌入到sklearn中,程式碼套路完全一樣

from xgboost import XGBRegressor
params = [1,2,3,4,5]
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(test_score)

完全一樣的程式碼套路。

相關文章