数据挖掘实战总结

零、 引言

此篇文章的初版,是笔者照着kaggle竞赛社区中Titanic项目中的两篇文章实战后的总结,两篇文章分别为:

  1. Titanic Data Science Solutions

    第一篇文章是以Titanic项目为例完完整整的介绍了一遍数据挖掘实战从理解数据到训练模型最后提交的整个过程,跟着实现一遍可以很清楚的理解与感知数据挖掘实战全过程,非常有助于培养实战的感觉

  2. Introduction to Ensembling/Stacking in Python

    第二篇文章也是一个以Titanic项目为例完整介绍了实战过程的文章,但是这篇文章的重心在于介绍与实践数据挖掘的集成算法 — Stacking 算法

一、 实战过程及常用方法

0. 理解题目与观察数据

- 理解题目

接手任何一竞赛或者项目的时候,第一件事都是要认真的阅读题目,充分理解题目的背景,因为每个项目虽然大体上的流程是差不多,但是每一个步骤的实现都会不一样,例如特征提取与选择方面,除去利用数学知识降维或者提取主要特征之外,还有一个很重要的方面,就是需要理解题目的业务场景,代入背景去思考业务的情况,这种做法可以让我们事先加强对特征的理解,方便我们判断特征工程过程中的合理性,也可以在一些项目场景中利用其特有的数据特征来修正这种场景下的模型已达到很好的效果

这种对于业务场景的思考应是贯彻到整个项目实战过程中的

- 观察数据

初步题目后,紧接着就是对于数据的观察和思考,python中利用pandas进行数据的加载和处理非常方便,其中pandas库中的一些观察数据的方法有

import pandas as pd
train_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 features
  • Creating new feature extracting from existing || Create new feature combining existing features
  • Converting a categorical feature || Converting categorical feature to numeric
  • Completing 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.pointplot
grid = 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.RdBu
plt.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 Regression
  • KNN or k-Nearest Neighbors
  • Support Vector Machines
  • Naive Bayes classifier
  • Decision Tree
  • Random Forrest
  • Xgboost

- Stacking 算法

此处额外需要讲述一种集成算法 —Stacking 集成算法,以两层Stacking 算法为例:

第一层,可以挑选 4 种或 5 种分类算法,记为model_amodel_bmodel_cmodel_dmodel_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_setmodel_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_bmodel_cmodel_dmodel_e四个模型,我们同样会各训练五遍,也就自然会产生model_list_bmodel_list_cmodel_list_dmodel_list_e,分别存储的是四个模型对于全部训练数据的预测值,还会产生每个模型的对于测试数据test_set的平均预测结果 model_b_testmodel_c_testmodel_d_testmodel_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_trainx_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 on
ntrain = train.shape[0]
ntest = test.shape[0]
SEED = 0 # for reproducibility
NFOLDS = 5 # set folds for out-of-fold prediction
kf = 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),并且会总结一些其它重要的算法,此处挖坑GBDTxgboost

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容