05.23 技術專欄-數據挖掘實戰總結

內容導讀從統計的角度說哪些數據特徵與待解決目標之間有較大相關性?訓練集中的數據特徵值改變後待解決目標值是否也一樣變化,並且反之亦然?在建模階段,需要準備適合模型訓練的數據。根據模型算法的選擇,可能需要將所有特徵轉換為等價的數值。數據準備過程也可能要求我們估計特徵中的任何缺失值。一種方法是檢測樣本或特徵中的任何異常值。零、 引言

此篇文章的初版,是筆者照著kaggle競賽社區中Titanic項目中的兩篇文章實戰後的總結,兩篇文章分別為:

Titanic Data Science Solutions第一篇文章是以Titanic項目為例完完整整的介紹了一遍數據挖掘實戰從理解數據到訓練模型最後提交的整個過程,跟著實現一遍可以很清楚的理解與感知數據挖掘實戰全過程,非常有助於培養實戰的感覺Introduction to Ensembling/Stacking in Python第二篇文章也是一個以Titanic項目為例完整介紹了實戰過程的文章,但是這篇文章的重心在於介紹與實踐數據挖掘的集成算法 — Stacking 算法一、 實戰過程及常用方法

0. 理解題目與觀察數據

- 理解題目

接手任何一競賽或者項目的時候,第一件事都是要認真的閱讀題目,充分理解題目的背景,因為每個項目雖然大體上的流程是差不多,但是每一個步驟的實現都會不一樣,例如特徵提取與選擇方面,除去利用數學知識降維或者提取主要特徵之外,還有一個很重要的方面,就是需要理解題目的業務場景,代入背景去思考業務的情況,這種做法可以讓我們事先加強對特徵的理解,方便我們判斷特徵工程過程中的合理性,也可以在一些項目場景中利用其特有的數據特徵來修正這種場景下的模型已達到很好的效果

這種對於業務場景的思考應是貫徹到整個項目實戰過程中的

- 觀察數據

初步題目後,緊接著就是對於數據的觀察和思考,python中利用pandas進行數據的加載和處理非常方便,其中pandas庫中的一些觀察數據的方法有

import pandas as pdtrain_df = pd.read_csv('./data/train.csv')train_df.head()train_df.info()# describe() 用於觀察連續數值特徵train_df.describe()# describe(include=['O']) 用於觀察字符串特徵及非連續值分類特徵train_df.describe(include=['O'])其中describe()是個很有效的描述數據的方法,可以加入percentiles=[.1, .2, .3, .4, .5, .6, .7]這樣的分位參數來將連續數值特徵排序並顯示分位值。描述分類特徵則可以返回特徵值的個數、頻率等值

一般觀察思考數據是結合業務場景的,需要理解什麼樣的場景下會產生這樣的數據,哪些數據特徵與結果存在明顯的對應關係等,在採取合適的操作之前應該有一些我們自己的關於數據的假設,然後在數據中佐證我們的假設

1. 分析數據與特徵工程

We need arrive at following assumptions based on data analysis done so far. We may validate these assumptions further before taking appropriate actions.上句是借用第一篇文章的一句話,也是我們這一部分的思考,數據分析比較多的都是用數據來驗證我們的假想,然後再採取更合適的操作

- 特徵工程部分的工作流程需要解決七個主要目標:

歸類(Classifying):需要嘗試分類或者歸類我們的樣例,並且去理解分出的不同的類別的含義及其與我們的目標之間的關聯關聯(Correlating):一種方法是利用訓練數據集中可用的數據特徵(feature)。哪些數據集中的特徵對我們的解決方案目標有顯著作用?從統計的角度說哪些數據特徵與待解決目標之間有較大相關性?訓練集中的數據特徵值改變後待解決目標值是否也一樣變化,並且反之亦然?這些都可以針對給定數據集中的數值特徵和分類特徵進行測試。我們也想要確定各個數據特徵之間的相關性,關聯一些確定的數據特徵可以有效地幫助我們創建、完善或者糾正其他的數據特徵轉化(Converting):在建模階段,需要準備適合模型訓練的數據。根據模型算法的選擇,可能需要將所有特徵轉換為等價的數值。例如將文本分類值特徵轉換數值特徵完善(Completing):數據準備過程也可能要求我們估計特徵中的任何缺失值。 當沒有缺失值時,模型算法可能效果最好糾正(Correcting)

:我們還可以分析給定的訓練數據集以查找錯誤或可能無法使用的特徵值,並嘗試糾正這些值或排除包含錯誤的樣本。 一種方法是檢測樣本或特徵中的任何異常值。 如果某項特徵對分析沒有貢獻,或者可能會顯著影響結果,我們也可能會完全放棄該特徵創造(Creating):我們可以基於現有的特徵或者一系列特徵創造新的數據特徵,且新特徵遵循相關性,轉換成數值和完整性目標圖表(Charting):根據數據的性質和解決方案目標來選擇正確的可視化圖表和圖表上述的七個方向不僅是特徵工程部分我們需要思考的,也是我們進行數據分析處理的七個角度

所以對應的數據清洗操作就可包含:

Correcting by dropping featuresCreating new feature extracting from existing || Create new feature combining existing featuresConverting a categorical feature || Converting categorical feature to numericCompleting numerical continuous feature || Completing a categorical feature- 數據分析常用的方法有

Analyze by pivoting feature

train_df[['feature1', 'feature2']].groupby(['feature1 or feature2'], as_index=False).mean().sort_values(by='feature1 or feature2', ascending=False)Analyze by visualizing data

# 利用 seaborn 畫圖# sns.barplot | plt.hist | sns.pointplotgrid = sns.FacetGrid(train_df, col='feature1', row='feature2', size=2.2, aspect=1.6)grid.map(plt.hist, 'feature3', alpha=.5, bins=20)grid.add_legend()grid = sns.FacetGrid(train_df, row='Embarked', size=2.2, aspect=1.6)grid.map(sns.pointplot, 'Pclass', 'Survived', 'Sex', palette='deep')grid.add_legend()plt.show()# 特徵值相關性的熱力圖colormap = plt.cm.RdBuplt.figure(figsize=(14,12))plt.title('Correlation of Features', y=1.05, size=15)sns.heatmap(train.astype(float).corr(),linewidths=0.1,vmax=1.0, square=True, cmap=colormap, linecolor='white', annot=True)g = sns.pairplot(train[[u'Survived', u'Pclass', u'Sex', u'Age', u'Parch', u'Fare', u'Embarked', u'FamilySize', u'Title']], hue='Survived', palette = 'seismic',size=1.2,diag_kind = 'kde',diag_kws=dict(shade=True),plot_kws=dict(s=10) )g.set(xticklabels=[])# 利用 plotly 畫圖 # go.Scatter | go.Bar trace = go.Scatter( y = feature_dataframe['Random Forest feature importances'].values, x = feature_dataframe['features'].values, mode='markers', marker=dict( sizemode = 'diameter', sizeref = 1, size = 25,# size= feature_dataframe['AdaBoost feature importances'].values, #color = np.random.randn(500), #set color equal to a variable color = feature_dataframe['Random Forest feature importances'].values, colorscale='Portland', showscale=True ), text = feature_dataframe['features'].values)data = [trace]layout= go.Layout( autosize= True, title= 'Random Forest Feature Importance', hovermode= 'closest',# xaxis= dict(# title= 'Pop',# ticklen= 5,# zeroline= False,# gridwidth= 2,# ), yaxis=dict( title= 'Feature Importance', ticklen= 5, gridwidth= 2 ), showlegend= False)fig = go.Figure(data=data, layout=layout)py.iplot(fig,filename='scatter2010')# 用 plotly 畫熱力圖data = [ go.Heatmap( z= base_predictions_train.astype(float).corr().values , x=base_predictions_train.columns.values, y= base_predictions_train.columns.values, colorscale='Viridis', showscale=True, reversescale = True )]py.iplot(data, filename='labelled-heatmap')2. 模型訓練與預測

這裡是對於數據挖掘算法的選擇,一般分類用的算法包括:

Logistic RegressionKNN or k-Nearest NeighborsSupport Vector MachinesNaive Bayes classifierDecision TreeRandom ForrestXgboost- Stacking 算法

此處額外需要講述一種集成算法 —Stacking 集成算法,以兩層Stacking 算法為例:

第一層,可以挑選 4 種或 5 種分類算法,記為model_a、model_b、model_c、model_d及model_e

對訓練數據進行訓練,此時就需要注意,在Stacking算法中,對訓練數據的模型訓練需要用到 K-折交叉驗證 方法以 5-折交叉驗證 為例:

首先假設我們有 m * n維度的訓練數據train_set以及k * w維度的測試數據test_set,把train_set分為5份,取出其中的 4 份作為新的(4/5)m * n維度的訓練數據記為tr_set,另一份則作為臨時的(1/5)m * n維度的測試數據記為te_set,假設模型model_a,利用tr_set對model_a進行訓練,訓練好的模型來預測餘下的一份te_set,得到的結果為(1/5)m * 1維度,用一種m * 1維度的數據結構model_list_a中的一部分記錄下來,然後繼續用此時的model_a預測全部的測試數據,得到結果model_a_tmp_1

因為是 **5-折 **交叉驗證,所以這個過程會重複五遍,即model_a模型會被不同的(4/5)m * n維度的訓練數據訓練五遍,最終的model_list_a裡保存的則是model_a對於所有訓練數據的預測值,每一次的重複又會產生不同的model_a_tmp_(2,3,4,5),將這些model_a_tmp相加求平均得model_a_test

而又因為我們選擇了五個訓練模型,所以對於model_b、model_c、model_d及model_e四個模型,我們同樣會各訓練五遍,也就自然會產生model_list_b,model_list_c,model_list_d及model_list_e,分別存儲的是四個模型對於全部訓練數據的預測值,還會產生每個模型的對於測試數據test_set的平均預測結果 model_b_test、model_c_test、model_d_test及model_e_test

然後將得到的結果拼接,如下代碼實現:

x_train = np.concatenate(( model_list_a, model_list_b, model_list_c, model_list_d, model_list_e), axis=1)x_test = np.concatenate(( model_a_test, model_b_test, model_c_test, model_d_test, model_e_test), axis=1)此時得到的x_train的數據結構可能是這樣的

技術專欄-數據挖掘實戰總結

屏幕快照 2018-05-21 下午11.06.43.png

我們就是利用這個 x_train 與 x_test 進行 stacking 算法的第二層訓練,例如利用xgboost算法進行訓練,如下:

gbm = xgb.XGBClassifier( #learning_rate = 0.02, n_estimators= 2000, max_depth= 4, min_child_weight= 2, #gamma=1, gamma=0.9, subsample=0.8, colsample_bytree=0.8, objective= 'binary:logistic', nthread= -1, scale_pos_weight=1).fit(x_train, y_train)predictions = gbm.predict(x_test)則此時得到的predictions就是我們利用Stacking算法集成了很多種基礎算法得到的最終結果

這個過程中有一個難點就是關於每個模型利用 k-折交叉驗證 的思想進行的 k 次重複訓練,實現代碼如下:

# Some useful parameters which will come in handy later onntrain = train.shape[0]ntest = test.shape[0]SEED = 0 # for reproducibilityNFOLDS = 5 # set folds for out-of-fold predictionkf = KFold(ntrain, n_folds= NFOLDS, random_state=SEED)def get_oof(clf, x_train, y_train, x_test): oof_train = np.zeros((ntrain,)) oof_test = np.zeros((ntest,)) oof_test_skf = np.empty((NFOLDS, ntest)) for i, (train_index, test_index) in enumerate(kf): x_tr = x_train[train_index] y_tr = y_train[train_index] x_te = x_train[test_index] clf.train(x_tr, y_tr) oof_train[test_index] = clf.predict(x_te) oof_test_skf[i, :] = clf.predict(x_test) oof_test[:] = oof_test_skf.mean(axis=0) return oof_train.reshape(-1, 1), oof_test.reshape(-1, 1)此外推薦閱讀 數據比賽大殺器----模型融合(stacking&blending),並且會總結一些其它重要的算法,此處挖坑GBDT、xgboost


分享到:


相關文章: