广州的房价是我遥不可及的梦,今天就用Python来做一个房价预测小工具。
哈嘍,大家好。
今天給大家介紹一個(gè)非常適合新手入門的機(jī)器學(xué)習(xí)實(shí)戰(zhàn)案例。
這是一個(gè)房價(jià)預(yù)測的案例,來源于?Kaggle?網(wǎng)站,是很多算法初學(xué)者的第一道競賽題目。
該案例有著解機(jī)器學(xué)習(xí)問題的完整流程,包含EDA、特征工程、模型訓(xùn)練、模型融合等。
房價(jià)預(yù)測流程
下面跟著我,來學(xué)習(xí)一下該案例。
沒有啰嗦的文字,沒有多余的代碼,只有通俗的講解。
1. EDA
探索性數(shù)據(jù)分析(Exploratory Data Analysis,簡稱EDA) 的目的是讓我們對(duì)數(shù)據(jù)集有充分的了解。在這一步,我們探索的內(nèi)容如下:
EDA內(nèi)容
1.1 輸入數(shù)據(jù)集
train?=?pd.read_csv('./data/train.csv') test?=?pd.read_csv('./data/test.csv')訓(xùn)練樣本
train和test分別是訓(xùn)練集和測試集,分別有 1460 個(gè)樣本,80 個(gè)特征。
SalePrice列代表房價(jià),是我們要預(yù)測的。
1.2 房價(jià)分布
因?yàn)槲覀內(nèi)蝿?wù)是預(yù)測房價(jià),所以在數(shù)據(jù)集中核心要關(guān)注的就是房價(jià)(SalePrice) 一列的取值分布。
sns.distplot(train['SalePrice']);房價(jià)取值分布
從圖上可以看出,SalePrice列峰值比較陡,并且峰值向左偏。
也可以直接調(diào)用skew()和kurt()函數(shù)計(jì)算SalePrice具體的偏度和峰度值。
對(duì)于偏度和峰度都比較大的情況,建議對(duì)SalePrice列取log()進(jìn)行平滑。
1.3 與房價(jià)相關(guān)的特征
了解完SalePrice的分布后,我們可以計(jì)算 80 個(gè)特征與SalePrice的相關(guān)關(guān)系。
重點(diǎn)關(guān)注與SalePrice相關(guān)性最強(qiáng)的 10 個(gè)特征。
#?計(jì)算列之間相關(guān)性 corrmat?=?train.corr()#?取?top10 k?=?10 cols?=?corrmat.nlargest(k,?'SalePrice')['SalePrice'].index#?繪圖 cm?=?np.corrcoef(train[cols].values.T) sns.set(font_scale=1.25) hm?=?sns.heatmap(cm,?cbar=True,?annot=True,?square=True,?fmt='.2f',?annot_kws={'size':?10},?yticklabels=cols.values,?xticklabels=cols.values) plt.show()與SalePrice高度相關(guān)的特征
OverallQual(房子材料和裝飾)、GrLivArea(地上居住面積)、GarageCars(車庫容量)和?TotalBsmtSF(地下室面積)跟SalePrice有很強(qiáng)的相關(guān)性。
這些特征在后面做特征工程時(shí)也會(huì)重點(diǎn)關(guān)注。
1.4 剔除離群樣本
由于數(shù)據(jù)集樣本量很少,離群點(diǎn)不利于我們后面訓(xùn)練模型。
所以需要計(jì)算每個(gè)數(shù)值特性的離群點(diǎn),剔除掉離群次數(shù)最多的樣本。
#?獲取數(shù)值型特征 numeric_features?=?train.dtypes[train.dtypes?!=?'object'].index#?計(jì)算每個(gè)特征的離群樣本 for?feature?in?numeric_features:outs?=?detect_outliers(train[feature],?train['SalePrice'],top=5,?plot=False)all_outliers.extend(outs)#?輸出離群次數(shù)最多的樣本 print(Counter(all_outliers).most_common())#?剔除離群樣本 train?=?train.drop(train.index[outliers])detect_outliers()是自定義函數(shù),用sklearn庫的LocalOutlierFactor算法計(jì)算離群點(diǎn)。
到這里, EDA 就完成了。最后,將訓(xùn)練集和測試集合并,進(jìn)行下面的特征工程。
y?=?train.SalePrice.reset_index(drop=True) train_features?=?train.drop(['SalePrice'],?axis=1) test_features?=?test features?=?pd.concat([train_features,?test_features]).reset_index(drop=True)features合并了訓(xùn)練集和測試集的特征,是我們下面要處理的數(shù)據(jù)。
2. 特征工程
特征工程
2.1 校正特征類型
MSSubClass(房屋類型)、YrSold(銷售年份)和MoSold(銷售月份)是類別型特征,只不過用數(shù)字來表示,需要將它們轉(zhuǎn)成文本特征。
features['MSSubClass']?=?features['MSSubClass'].apply(str) features['YrSold']?=?features['YrSold'].astype(str) features['MoSold']?=?features['MoSold'].astype(str)2.2 填充特征缺失值
填充缺失值沒有統(tǒng)一的標(biāo)準(zhǔn),需要根據(jù)不同的特征來決定按照什么樣的方式來填充。
# Functional:文檔提供了典型值 Typ features['Functional']?=?features['Functional'].fillna('Typ')?#Typ?是典型值#?分組填充需要按照相似的特征分組,取眾數(shù)或中位數(shù) #?MSZoning(房屋區(qū)域)按照?MSSubClass(房屋)類型分組填充眾數(shù) features['MSZoning']?=?features.groupby('MSSubClass')['MSZoning'].transform(lambda?x:?x.fillna(x.mode()[0]))#LotFrontage(到接到舉例)按Neighborhood分組填充中位數(shù) features['LotFrontage']?=?features.groupby('Neighborhood')['LotFrontage'].transform(lambda?x:?x.fillna(x.median()))#?車庫相關(guān)的數(shù)值型特征,空代表無,使用0填充空值。 for?col?in?('GarageYrBlt',?'GarageArea',?'GarageCars'):features[col]?=?features[col].fillna(0)2.3 偏度校正
跟探索SalePrice列類似,對(duì)偏度高的特征進(jìn)行平滑。
# skew()方法,計(jì)算特征的偏度(skewness)。 skew_features?=?features[numeric_features].apply(lambda?x:?skew(x)).sort_values(ascending=False)#?取偏度大于?0.15?的特征 high_skew?=?skew_features[skew_features?>?0.15] skew_index?=?high_skew.index#?處理高偏度特征,將其轉(zhuǎn)化為正態(tài)分布,也可以使用簡單的log變換 for?i?in?skew_index:features[i]?=?boxcox1p(features[i],?boxcox_normmax(features[i]?+?1))2.4 特征刪除和新增
對(duì)于幾乎都是缺失值,或單一取值占比高(99.94%)的特征可以直接刪除。
features?=?features.drop(['Utilities',?'Street',?'PoolQC',],?axis=1)?同時(shí),可以融合多個(gè)特征,生成新特征。
有時(shí)候模型很難學(xué)習(xí)到特征之間的關(guān)系,手動(dòng)融合特征可以降低模型學(xué)習(xí)難度,提升效果。
#?將原施工日期和改造日期融合 features['YrBltAndRemod']=features['YearBuilt']+features['YearRemodAdd']#?將地下室面積、1樓、2樓面積融合 features['TotalSF']=features['TotalBsmtSF']?+?features['1stFlrSF']?+?features['2ndFlrSF']可以發(fā)現(xiàn),我們?nèi)诤系奶卣鞫际桥cSalePrice強(qiáng)相關(guān)的特征。
最后簡化特征,對(duì)分布單調(diào)的特征(如:100個(gè)數(shù)據(jù)中有99個(gè)的數(shù)值是0.9,另1個(gè)是0.1),進(jìn)行01處理。
features['haspool']?=?features['PoolArea'].apply(lambda?x:?1?if?x?>?0?else?0)features['has2ndfloor']?=?features['2ndFlrSF'].apply(lambda?x:?1?if?x?>?0?else?0)2.6 生成最終訓(xùn)練數(shù)據(jù)
到這里特征工程就做完了, 我們需要從features中將訓(xùn)練集和測試集重新分離出來,構(gòu)造最終的訓(xùn)練數(shù)據(jù)。
X?=?features.iloc[:len(y),?:]? X_sub?=?features.iloc[len(y):,?:]X?=?np.array(X.copy()) y?=?np.array(y) X_sub?=?np.array(X_sub.copy())3. 模型訓(xùn)練
因?yàn)镾alePrice是數(shù)值型且是連續(xù)的,所以需要訓(xùn)練一個(gè)回歸模型。
3.1 單一模型
首先以嶺回歸(Ridge)?為例,構(gòu)造一個(gè)k折交叉驗(yàn)證模型。
from?sklearn.linear_model?import?RidgeCV from?sklearn.pipeline?import?make_pipeline from?sklearn.model_selection?import?KFoldkfolds?=?KFold(n_splits=10,?shuffle=True,?random_state=42)alphas_alt?=?[14.5,?14.6,?14.7,?14.8,?14.9,?15,?15.1,?15.2,?15.3,?15.4,?15.5]ridge?=?make_pipeline(RobustScaler(),?RidgeCV(alphas=alphas_alt,?cv=kfolds))嶺回歸模型有一個(gè)超參數(shù)alpha,而RidgeCV的參數(shù)名是alphas,代表輸入一個(gè)超參數(shù)alpha數(shù)組。在擬合模型時(shí),會(huì)從alpha數(shù)組中選擇表現(xiàn)較好某個(gè)取值。
由于現(xiàn)在只有一個(gè)模型,無法確定嶺回歸是不是最佳模型。所以我們可以找一些出場率高的模型多試試。
#?lasso lasso?=?make_pipeline(RobustScaler(),LassoCV(max_iter=1e7,?alphas=alphas2,?random_state=42,?cv=kfolds))#elastic?net elasticnet?=?make_pipeline(RobustScaler(),ElasticNetCV(max_iter=1e7,?alphas=e_alphas,?cv=kfolds,?l1_ratio=e_l1ratio))#svm svr?=?make_pipeline(RobustScaler(),?SVR(C=20,epsilon=0.008,gamma=0.0003, ))#GradientBoosting(展開到一階導(dǎo)數(shù)) gbr?=?GradientBoostingRegressor(...)#lightgbm lightgbm?=?LGBMRegressor(...)#xgboost(展開到二階導(dǎo)數(shù)) xgboost?=?XGBRegressor(...)有了多個(gè)模型,我們可以再定義一個(gè)得分函數(shù),對(duì)模型評(píng)分。
#模型評(píng)分函數(shù) def?cv_rmse(model,?X=X):rmse?=?np.sqrt(-cross_val_score(model,?X,?y,?scoring="neg_mean_squared_error",?cv=kfolds))return?(rmse)以嶺回歸為例,計(jì)算模型得分。
score?=?cv_rmse(ridge)?print("Ridge?score:?{:.4f}?({:.4f})\n".format(score.mean(),?score.std()),?datetime.now(),?)?#0.1024運(yùn)行其他模型發(fā)現(xiàn)得分都差不多。
這時(shí)候我們可以任選一個(gè)模型,擬合,預(yù)測,提交訓(xùn)練結(jié)果。還是以嶺回歸為例
#?訓(xùn)練模型 ridge.fit(X,?y)#?模型預(yù)測 submission.iloc[:,1]?=?np.floor(np.expm1(ridge.predict(X_sub)))#?輸出測試結(jié)果 submission?=?pd.read_csv("./data/sample_submission.csv") submission.to_csv("submission_single.csv",?index=False)submission_single.csv是嶺回歸預(yù)測的房價(jià),我們可以把這個(gè)結(jié)果上傳到 Kaggle 網(wǎng)站查看結(jié)果的得分和排名。
3.2 模型融合-stacking
有時(shí)候?yàn)榱税l(fā)揮多個(gè)模型的作用,我們會(huì)將多個(gè)模型融合,這種方式又被稱為集成學(xué)習(xí)。
stacking?是一種常見的集成學(xué)習(xí)方法。簡單來說,它會(huì)定義個(gè)元模型,其他模型的輸出作為元模型的輸入特征,元模型的輸出將作為最終的預(yù)測結(jié)果。
stacking
這里,我們用mlextend庫中的StackingCVRegressor模塊,對(duì)模型做stacking。
stack_gen?=?StackingCVRegressor(regressors=(ridge,?lasso,?elasticnet,?gbr,?xgboost,?lightgbm),meta_regressor=xgboost,use_features_in_secondary=True)訓(xùn)練、預(yù)測的過程與上面一樣,這里不再贅述。
3.3 模型融合-線性融合
多模型線性融合的思想很簡單,給每個(gè)模型分配一個(gè)權(quán)重(權(quán)重加和=1),最終的預(yù)測結(jié)果取各模型的加權(quán)平均值。
#?訓(xùn)練單個(gè)模型 ridge_model_full_data?=?ridge.fit(X,?y) lasso_model_full_data?=?lasso.fit(X,?y) elastic_model_full_data?=?elasticnet.fit(X,?y) gbr_model_full_data?=?gbr.fit(X,?y) xgb_model_full_data?=?xgboost.fit(X,?y) lgb_model_full_data?=?lightgbm.fit(X,?y) svr_model_full_data?=?svr.fit(X,?y)models?=?[ridge_model_full_data,?lasso_model_full_data,?elastic_model_full_data,gbr_model_full_data,?xgb_model_full_data,?lgb_model_full_data,svr_model_full_data,?stack_gen_model ]#?分配模型權(quán)重 public_coefs?=?[0.1,?0.1,?0.1,?0.1,?0.15,?0.1,?0.1,?0.25]#?線性融合,取加權(quán)平均 def?linear_blend_models_predict(data_x,models,coefs,?bias):tmp=[model.predict(data_x)?for?model?in?models]tmp?=?[c*d?for?c,d?in?zip(coefs,tmp)]pres=np.array(tmp).swapaxes(0,1)?pres=np.sum(pres,axis=1)return?pres到這里,房價(jià)預(yù)測的案例我們就講解完了,大家可以自己運(yùn)行一下,看看不同方式訓(xùn)練出來的模型效果。
回顧整個(gè)案例會(huì)發(fā)現(xiàn),我們在數(shù)據(jù)預(yù)處理和特征工程上花費(fèi)了很大心思,雖然機(jī)器學(xué)習(xí)問題模型原理比較難學(xué),但實(shí)際過程中往往特征工程花費(fèi)的心思最多。
完整源代碼關(guān)注公眾號(hào):Python源碼?即可獲取
總結(jié)
以上是生活随笔為你收集整理的广州的房价是我遥不可及的梦,今天就用Python来做一个房价预测小工具。的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: arcengin交互式动图制作
- 下一篇: [转载].NET商业软件源码保护