基于数据分析的web安全检测

算法分析与设计
网络攻防大实验
云安全与大数据

零、kaggle简介

Kaggle是由联合创始人、首席执行官安东尼·高德布卢姆(Anthony Goldbloom)2010年在墨尔本创立的,主要为开发商和数据科学家提供举办机器学习竞赛、托管数据库、编写和分享代码的平台。该平台已经吸引了80万名数据科学家的关注,这些用户资源或许正是吸引谷歌的主要因素。

正如某位技术总监所说的那样,如果你在比赛中打进10%,那么你就有机会得到一次大厂的面试。如果你打进5%,那么你就有直聘的机会。如果你打进1%,那你就能和业界大牛谈笑风生。滑稽

参加kaggle是一种怎样的体验?

作者:知乎用户
链接:https://www.zhihu.com/question/24533374/answer/317125642
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

转眼到了2018了,大家能明显得感受到,kaggle上data mining的比重越来越少,CV,NLP,优化赛,承办会议赛题越来越多,比如非常有意思的NIPS的对抗攻防,知名度和整体水平都越来越好,体验就是,拿奖牌越来越难。绝不是xgb融合就能轻松搞定的打一个比赛,往往需要无所不用其极,需要你对这个问题相关的方法非常熟悉,并且能够实践。比如去年的quora提供的赛题,中科院师兄的方案就让人叹为观止,你能感受到,他们对信息检索中文本相似度相关的研究如数家珍。对具体的任务也有非常深刻的见解,比赛中提出的pipeline也与中科院的自动化框架一脉相承,看罢收获颇丰。在这个方向上的研究又在CIkM的workshop上拿了best。这两者往往是相互促进的。如果说做科研需要你对问题有insight的理解,那么打比赛比的就是需要你对数据有insight的理解。通过打比赛,能够培养你的科研审美,更能深刻的理解什么是在数据上的过拟合,你会熟知论文中的方法是不是有良好的泛化性能,是不是真的stateofart,在别的数据集上能否经得起考验。很多东西通过比赛中在学界和工业界产出了非常好的影响力。比如imagine net带来深度学习的风潮。Netflix中的分解机。kdd cup以kaggle中天奇大佬的xgboost, 微软的lightgbm。Kaggle是一个非常友好的社区,大家都乐于分享,这与国内的平台形成了鲜明的对比。如果你是一个机器学习初学者,想快速提升实践能力,那么kaggle是个非常好的地方。如果你想拿大厂的sp,我觉得master的影响力也足够,毕竟全球才1000个,可以堪比ijcai和aaai这两个国人热衷的顶会,滑稽

一、数据集简介

enter description here

1.png

这是kaggle上的一个关于安全的比赛。其中,malicious代表恶意,benign代表恶性。
我之所以选择这个数据集,主要原因是因为它比较小。安全方面的数据挖掘在kaggle上并不是很多,微软倒是有一个,不过那个是安卓恶意软件检测分析,光是训练集解压之后就有整整500多G(此乃CPU不能承受之重),果断放弃。

二、开始挖矿之旅

1.肉眼观察

数据集的格式是一如既往的CSV
当然了,那些python的常用库也是一个也少不了的。

import pandas as pd
import numpy as np
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.linear_model import LinearRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score

读取CSV文件

df=pd.read_csv("security.csv")
df.shape

读取CSV文件

2.png

查看一下每一列的信息(至于这些词汇的具体含义,就触及到了我的知识盲区了。)
enter description here
再来查看一下info
enter description here
然后查看一下前十个数据
enter description here
然后就是对每一列的信息进行观测
enter description here
enter description here

单纯依靠这些信息还得不出什么结论,因此我们需要借助于一些统计学的知识对数据进行进一步的观测。比如看看他们的直方图,饼状图,箱型图。在这里,我们首先使用直方图进行观测。

plt.figure(figsize=(16,8))
sns.countplot(data=df, x='WHOIS_REG_YEAR', hue='TIPO')

enter description here

9.png

黄色代表恶性,蓝色代表良性。
X轴为WHOIS_REG_YEAR
Y轴为数量

plt.figure(figsize=(16,8))
sns.countplot(data=df, x='WHOIS_COUNTRY', hue='TIPO')

enter description here

10.png

plt.figure(figsize=(16,8))
sns.countplot(data=df, x='TCP_CONVERSATION_EXCHANGE', hue='TIPO')

enter description here

11.png

下图是域名和恶性网站之间的关系
enter description here
enter description here
在1600个数据中,有152次恶性网站的记录
enter description here
这些网站是这样的:
enter description here
我们找两个看看:
enter description here
enter description here
看起来挺正规的,不知道是不是被挂马了

看完直方图,最后再看一眼热度图,在此之前,我们还要完成两个操作。第一个操作是将标签二值化。标签列名为TIPO,其中只有两种数据,一个是Maligna,代表恶性;一个是Benigna,代表良性。
enter description here
还有一些string类型的变量也要处理一下。
enter description here
这些变量在默认的情况下会被pandas处理为独热编码,当然你也可以自主映射。
好了,来看热度图吧!

enter description here

18.png

颜色越明亮,说明相关性越高。中间那一条白线的值全都是0,看来这一列没什么卵用,等会删了。
enter description here
所以,为了节省计算开支,我们先把那些没卵用的变量给删掉。

new_df=new_df.drop(['TIPO','CHARSET','CACHE_CONTROL'], axis=1)

之所以删除TIPO,是因为这一列都是二值化的标签,不能留在训练集中。

y = moddf['TIPO']

好了,直观感受到此为止。接下来我们需要用机器学习的方法对数据进行一些预处理了。是不是有点小兴奋呢?

2.数据预处理

因为当前只有一个CSV文件,所以我们要把数据集拆分成训练集和测试集。

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=100)

好了,我们开始疯狂导入机器学习算法,总之先搞一个base_line。
鲁迅曾经说过:“不要想着一开始就搞出一个屌炸天的pipe_line。”
enter description here

嗯,逻辑回归,朴素贝叶斯,随机森林,支持向量机,决策树,这些主要的分类算法都先过一遍看看效果。

最近邻分类器

enter description here

23.png

绘图
enter description here
从上图可以看出,随着K值的增加,错误率在不断的提升(滑稽),所以我们最终把K定为1
enter description here
其中包含准确率,召回值,F1-score,给大家科普一下。
enter description here
=参考链接
再来科普一下混淆矩阵
enter description here

好了,最近邻分类器就探索到这里,接下来我们对其他分类性能更强的分类器进行探索。

线性分类器

emmmmmmm,线性分类器的准确率只有58%
enter description here
鲁迅曾经说过。。。。算了
我们再用lasso试一下,毕竟线性分类器只有一条线,即使在鸢尾花这种非常容易分类的数据集上,线性分类器的准确率也只有0.36而已。

enter description here

29.png

lasso是含有惩罚系数的线性分类器,score会不超过1,而且也有为负值的可能(具体的准确率计算公式有兴趣请自行查询),这说明预测效果太差,所以lasso,OUT!

支持向量机

接下来我们就要对支持向量机,SVM,进行测试。
支持向量机可以说是传统机器学习和数据挖掘中的大杀器了。

科普一波:
支持向量机(Support Vector Machine,SVM)是Corinna Cortes和Vapnik等于1995年首先提出的,它在解决小样本、非线性及高维模式识别中表现出许多特有的优势,并能够推广应用到函数拟合等其他机器学习问题中。

在机器学习中,支持向量机(SVM,还支持矢量网络)是与相关的学习算法有关的监督学习模型,可以分析数据,识别模式,用于分类和回归分析。

要知道,vapnik曾经凭借一句话就让无数的机器学习从业者失业了(滑稽)

这里要说一下,之所以支持向量机牛逼,就在于它对样本数量不敏感,而且可以很轻松的抓住数据和特征之间的非线性关系,这个世界上,绝大多数问题都是非线性的。但是SVM对于数据缺失敏感,核函数计算复杂度高,好在本数据集中是没有缺失数据的。

言归正传,因为支持向量机的参数比较多,但主要的只有四个,所以我们要对这四个参数进行整体性测试。如果你的计算条件足够好,那么你可以进行更大规模的组合测试。

#对SVM进行整体性测试,主要测试参数包括degree,gamma,r,kernel
#其中,degree是一个整数。制定了当前核函数是多项式核函数的时候,多项式的系数。对于其他核函数无效
#gamma是一个浮点数,当核函数为 rbf,poly,sigmoid时,核函数的系数。
#r与参数coef0有关,指定了核函数中的自由项,只有当核函数为poly和sigmoid时有效
import matplotlib.pyplot as plt

def test_SVC_poly(*data):
    X_train,X_test,y_train,y_test = data
    fig = plt.figure()
    ###测试degree###
    degrees = range(1,20)
    train_scores = []
    test_scores = []
    for degree in  degrees:
        cls = SVC(kernel='poly',degree=degree)
        cls.fit(X_train,y_train)
        train_scores.append(cls.score(X_train,y_train))
        test_scores.append(cls.score(X_test,y_test))
        
    ax = fig.add_subplot(1,3,1)
    ax.plot(degrees,train_scores,labels = 'Trainning Scores',marker = '+')
    ax.plot(degrees,test_scores,labels = 'Testing Scores',marker = 'o')
    
    ax.set_title('SVC_POLY_DEGREE')
    ax.set_xlabel('p')
    ax.set_ylabel('score')
    ax.set_ylim(0,1.05)
    ax.legend(loc='best',framealpha = 0.5)
    
    ###测试gamma###
    gammas = range(1,20)
    train_scores = []
    test_scores = []
    for gamma in  gammas:
        cls = SVC(kernel='poly',degree=3,gamma=gamma)
        cls.fit(X_train,y_train)
        train_scores.append(cls.score(X_train,y_train))
        test_scores.append(cls.score(X_test,y_test))
        
    ax = fig.add_subplot(1,3,1)
    ax.plot(degrees,train_scores,labels = 'Trainning Scores',marker = '+')
    ax.plot(degrees,test_scores,labels = 'Testing Scores',marker = 'o')
    
    ax.set_title('SVC_POLY_GAMMA')
    ax.set_xlabel(r'$\gamma$')
    ax.set_ylabel('score')
    ax.set_ylim(0,1.05)
    ax.legend(loc='best',framealpha = 0.5)
    
    ###测试r######
    rs = range(0,20)
    train_scores = []
    test_scores = []
    for r in  rs:
        cls = SVC(kernel='poly',degree=3,gamma = 10,coef0 = r)
        cls.fit(X_train,y_train)
        train_scores.append(cls.score(X_train,y_train))
        test_scores.append(cls.score(X_test,y_test))
        
    ax = fig.add_subplot(1,3,1)
    ax.plot(degrees,train_scores,labels = 'Trainning Scores',marker = '+')
    ax.plot(degrees,test_scores,labels = 'Testing Scores',marker = 'o')
    
    ax.set_title('SVC_POLY_R')
    ax.set_xlabel(r'r')
    ax.set_ylabel('score')
    ax.set_ylim(0,1.05)
    ax.legend(loc='best',framealpha = 0.5)
    plt.show()

enter description here

36.png

单纯这幅图就用了将近八分钟的时间,range(1,5),我是在实验室的台式机上跑的。鲁迅曾经说过,光有好的算法也是不够的 ,还需要有硬件的支持。
而下面这幅图则花掉了我整整半个小时的时间,range(1,20)
有这么多时间,线性分类器早就能做完很多工作了。所以SVM虽好,但工业界仍旧偏爱线性分类和回归。
enter description here

同样,rbf核和sigmoid核也是需要经过类似的测试,然后对比准确率,手动选择最好的参数。

到此为止,SVM测试完毕。

决策树分类器

决策树是一种二叉分类树,简单强大,是base_line中的杠把子,用过的人都说好。
决策树模型在监督学习中非常常见,可用于分类(二分类、多分类)和回归。虽然将多棵弱决策树的Bagging、Random Forest、Boosting等tree ensembel 模型更为常见,但是“完全生长”决策树因为其简单直观,具有很强的解释性,也有广泛的应用,而且决策树是tree ensemble 的基础,值得好好理解。一般而言一棵“完全生长”的决策树包含,特征选择、决策树构建、剪枝三个过程,这篇文章主要是简单梳理比较ID3、C4.5、CART算法。《统计学习方法》中有比较详细的介绍。

一、决策树的优点和缺点

优点:

决策树算法中学习简单的决策规则建立决策树模型的过程非常容易理解,
决策树模型可以可视化,非常直观
应用范围广,可用于分类和回归,而且非常容易做多类别的分类
能够处理数值型和连续的样本特征
缺点:

很容易在训练数据中生成复杂的树结构,造成过拟合(overfitting)。剪枝可以缓解过拟合的负作用,常用方法是限制树的高度、叶子节点中的最少样本数量。
学习一棵最优的决策树被认为是NP-Complete问题。实际中的决策树是基于启发式的贪心算法建立的,这种算法不能保证建立全局最优的决策树。Random Forest 引入随机能缓解这个问题
二、ID3算法

  ID3由Ross Quinlan在1986年提出。ID3决策树可以有多个分支,但是不能处理特征值为连续的情况。决策树是一种贪心算法,每次选取的分割数据的特征都是当前的最佳选择,并不关心是否达到最优。在ID3中,每次根据“最大信息熵增益”选取当前最佳的特征来分割数据,并按照该特征的所有取值来切分,也就是说如果一个特征有4种取值,数据将被切分4份,一旦按某特征切分后,该特征在之后的算法执行中,将不再起作用,所以有观点认为这种切分方式过于迅速。ID3算法十分简单,核心是根据“最大信息熵增益”原则选择划分当前数据集的最好特征,信息熵是信息论里面的概念,是信息的度量方式,不确定度越大或者说越混乱,熵就越大。在建立决策树的过程中,根据特征属性划分数据,使得原本“混乱”的数据的熵(混乱度)减少,按照不同特征划分数据熵减少的程度会不一样。在ID3中选择熵减少程度最大的特征来划分数据(贪心),也就是“最大信息熵增益”原则。下面是计算公式,建议看链接计算信息上增益的实例。

enter description here

30.png

三、C4.5算法

  C4.5是Ross Quinlan在1993年在ID3的基础上改进而提出的。.ID3采用的信息增益度量存在一个缺点,它一般会优先选择有较多属性值的Feature,因为属性值多的Feature会有相对较大的信息增益?(信息增益反映的给定一个条件以后不确定性减少的程度,必然是分得越细的数据集确定性更高,也就是条件熵越小,信息增益越大).为了避免这个不足C4.5中是用信息增益比率(gain ratio)来作为选择分支的准则。信息增益比率通过引入一个被称作分裂信息(Split information)的项来惩罚取值较多的Feature。除此之外,C4.5还弥补了ID3中不能处理特征属性值连续的问题。但是,对连续属性值需要扫描排序,会使C4.5性能下降,有兴趣可以参考博客

enter description here

31.png

五、CART算法

 参考:CART使用GINI指数分类

 CART(Classification and Regression tree)分类回归树由L.Breiman,J.Friedman,R.Olshen和C.Stone于1984年提出。ID3中根据属性值分割数据,之后该特征不会再起作用,这种快速切割的方式会影响算法的准确率。CART是一棵二叉树,采用二元切分法,每次把数据切成两份,分别进入左子树、右子树。而且每个非叶子节点都有两个孩子,所以CART的叶子节点比非叶子多1。相比ID3和C4.5,CART应用要多一些,既可以用于分类也可以用于回归。CART分类时,使用基尼指数(Gini)来选择最好的数据分割的特征,gini描述的是纯度,与信息熵的含义相似。CART中每一次迭代都会降低GINI系数。下图显示信息熵增益的一半,Gini指数,分类误差率三种评价指标非常接近。回归时使用均方差作为loss function。基尼系数的计算与信息熵增益的方式非常类似,公式如下

enter description here

32.png

话不多说,我们来看看决策树模型的实战能力
enter description here
卧槽,看见没!默认参数条件下,决策树就展现出了这么牛逼的性能!
enter description here
可能是因为所有数据都是离散的,所以ID3的准确率比较高

最后我们在来测试一下决策树深度对于准确率的影响吧!

#因为决策树越深,模型复杂度越高,准确率也会提升,所以我们来对决策树的深度做一波测试
def test_depth(*data):
    X_train,X_test,y_train,y_test = data
    depths = range(1,20)
    trainning_scores = []
    testing_scores = []
    for depth in depths:
        clf = DecisionTreeClassifier(max_depth=depth)
        clf.fit(X_train,y_train)
        trainning_scores.append(clf.score(X_train,y_train))
        testing_scores.append(clf.score(X_test,y_test))
        
    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)
    ax.plot(depths,trainning_scores,label = 'trainning score',marker = 'o')
    ax.plot(depths,testing_scores,label = 'testing score',marker = '*')
    ax.set_xlabel('maxdepth')
    ax.set_ylabel('score')
    ax.set_title('DecisionTreeClassifier')
    ax.legend(framealpha=0.5,loc = 'best')
    plt.show()

enter description here

35.png

根据这张图片我们可以看出,决策树在深度方面还是有比较大的提升的。而这些参数的优化则需要更多的努力和更强大的计算条件。

boosting算法

如果说SVM属于大杀器,那么集成学习就属于屠龙刀+倚天剑这样的感觉。
其核心思想就是‘三个臭皮匠,顶个诸葛亮’,当多个性能一般的分类器集成在一起的时候,就会产生很强的预测能力,这一点已经被数学证明。正所谓大力出奇迹。

enter description here

38.png

集成学习在速度方面跟决策树差不多的感觉,性能方面比决策树要强一些。在kaggle比赛中,集成学习的使用非常广泛,而其中XGBoost算法更是绝大多数队伍用在最终模型的算法。

接下来我们探索一下AdaBoostClassifier的最优参数选择

estimators_ 是集成学习中最重要的参数,表示所有训练过的基础分类器的个数。我在之前也说过了,集成学习最核心的思想就是以量取胜,所以我们有必要探索一下estimators_

def test_AdaBoostClassifier(*data):
    X_train,X_test,y_train,y_test = data
    clf = AdaBoostClassifier(learning_rate=0.1)
    clf.fit(X_train,y_train)
    
    #绘图
    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)
    estimators_num = len(clf.estimators_)
    x = range(1,estimators_num+1)
    
    
    
    ax.plot(list(x),list(clf.staged_score(X_train,y_train)),label = 'trainning score')
    ax.plot(list(x),list(clf.staged_score(X_test,y_test)),label = 'testing score')
    ax.set_xlabel('estimator_number')
    ax.set_ylabel('score')
    ax.set_title('AdaBoostClassifier')
    ax.legend(loc = 'best')
    plt.show()

enter description here

39.png

由此可见,基础学习器的数量对准确率有很大影响,随着基础学习器个数的增加,准确率也会随之提升。
根据集成学习的数学公式我们可以知道,准确率的上界会随着基础分类器数量的增加而提升
enter description here
当然了,还有一个比较重要的参数就是基础学习器的类型。虽然说三个臭皮匠赛过诸葛亮,但是我们能不能把臭皮匠的个数压缩成两个呢?或者说把三个臭皮匠,换成三个能打的呢?

你只要吧上面的那段程序稍微改一改就可以了。

贝叶斯分类器

差点吧这个给忘了。
我们最后再测试一下伯努利贝叶斯分类器的性能。
enter description here
性能也还不错,就不调参了。

3.模型融合

用一个不是很恰当的栗子来说明这个模型融合,那就是盲人摸象。
如果说大象是整个样本空间的话,那么赛方提供的数据,是不可能全面的(因为赛方无法提供关于这个赛题数据的所有样本数据,他只可能是其中的一部分),可能只是尾巴的一部分+腿的一部分+耳朵的一部分+鼻子的一部分等等。那么每个盲人(模型),就相当于各种算法。厉害如诸葛亮一般的算法,他的手会更加的长,更加的细腻,他能更加准确的摸清数据中的细节特征和从而得出更靠谱的结论,而stacking技术呢,他能通过各个盲人(单模型)提供的结果,总结他们得出的结论,从而得出更靠谱的结论。

enter description here

41.jpg

根据上图分析一下stacking具体步骤:

  1)TrainingData进行5-fold分割,正好生成5个model,每个model预测训练数据的1/5部分,最后合起来正好是一个完整的训练集Predictions,行数与TrainingData一致。

  2)TestData数据,model1-model5每次都对TestData进行预测,形成5份完整的Predict(绿色部分),最后对这个5个Predict取平均值,得到测试集Predictions。

  3)上面的1)与2)步骤只是用了一种算法,如果用三种算法,就是三份“训练集Predictions与测试集Predictions”,可以认为就是形成了三列新的特征,训练集Predictions与测试集Predictions各三列。

  4)3列训练集Predictions+TrainingData的y值,就形成了新的训练样本数据;测试集Predictions的三列就是新的测试数据。

  5)利用meta model(模型上的模型),其实就是再找一种算法对上述新数据进行建模预测,预测出来的数据就是提交的最终数据。

备注:本例中第3)步中只说了三种算法形成三份训练集Predictions作为第二层的特征,其实三种特征有点少,容易overfitting,尽量多用一些算法,每种算法也可以根据hyperopt的搜索参数对应不同的模型,这样就会有很多模型产生,也就是会形成多份“训练集Predictions”以及多份“测试集Predictions”,这样在第5)建立的模型及预测的结果相对会好一些。

虽然他很直观,但是没有语言描述确实很难搞懂。

上半部分是用一个基础模型进行5折交叉验证,如:用XGBoost作为基础模型Model1,5折交叉验证就是先拿出四折作为training data,另外一折作为testing data。注意:在stacking中此部分数据会用到整个traing set。如:假设我们整个training set包含10000行数据,testing set包含2500行数据,那么每一次交叉验证其实就是对training set进行划分,在每一次的交叉验证中training data将会是8000行,testing data是2000行。

每一次的交叉验证包含两个过程,1. 基于training data训练模型;2. 基于training data训练生成的模型对testing data进行预测。在整个第一次的交叉验证完成之后我们将会得到关于当前testing data的预测值,这将会是一个一维2000行的数据,记为a1。注意!在这部分操作完成后,我们还要对数据集原来的整个testing set进行预测,这个过程会生成2500个预测值,这部分预测值将会作为下一层模型testing data的一部分,记为b1。因为我们进行的是5折交叉验证,所以以上提及的过程将会进行五次,最终会生成针对testing set数据预测的5列2000行的数据a1,a2,a3,a4,a5,对testing set的预测会是5列2500行数据b1,b2,b3,b4,b5。

在完成对Model1的整个步骤之后,我们可以发现a1,a2,a3,a4,a5其实就是对原来整个training set的预测值,将他们拼凑起来,会形成一个10000行一列的矩阵,记为A1。而对于b1,b2,b3,b4,b5这部分数据,我们将各部分相加取平均值,得到一个2500行一列的矩阵,记为B1。

以上就是stacking中一个模型的完整流程,stacking中同一层通常包含多个模型,假设还有Model2: LR,Model3:RF,Model4: GBDT,Model5:SVM,对于这四个模型,我们可以重复以上的步骤,在整个流程结束之后,我们可以得到新的A2,A3,A4,A5,B2,B3,B4,B5矩阵。

在此之后,我们把A1,A2,A3,A4,A5并列合并得到一个10000行五列的矩阵作为training data,B1,B2,B3,B4,B5并列合并得到一个2500行五列的矩阵作为testing data。让下一层的模型,基于他们进一步训练。

以上即为stacking的完整步骤!

首先我们来构建融合模型:

from sklearn.model_selection import KFold
kf = KFold(n_splits=5,random_state=20180526)

因为我们在之前已经构建了五个性能接近,都是96%准确率以上的分类器(线性回归删掉了),所以就用5折交叉验证。

紧接着我们将刚才在实验中得出的最优参数都保存在一个字典当中:

#我们将刚才从实验中获得的最有参数都保存在一个字典当中
#一共五个分类器,对应五折交叉运算
knn_pra = {#
    'n_neighbors':1
}

adaboost_pra = {#
    'n_estimators':50
}

Dtree_pra = {#
    'max_depth' : 11
}

svc_pra = {#
    'degree':1
}

rf_pra = {
    'criterion' : 'entropy'
}

构建一个类,作为分类器的打包器,这样我们就以在传入最优参数的同时轻松调用分类器的方法

class SklearnWrapper(object):
    def __init__(self, clf, seed=11, params=None):
        #params['random_state'] = seed
        self.clf = clf(**params)

    def train(self, x_train, y_train):
        self.clf.fit(x_train, y_train)

    def predict(self, x):
        return self.clf.predict(x)
    def score(self,x,y):
        return self.clf.score(x,y)

一下是stacking方法

def get_oof(clf):
    #ntrain = X_train.shape[0]
    #ntest = X_test.shape[0]
    
    oof_train = np.zeros((ntrain,))
    oof_test = np.zeros((ntest,))
    oof_test_skf = np.empty((5, ntest))

    
    for i, (train_index, test_index) in enumerate(kf.split(X_train)):
    #for train_index, test_index in kf.split(X_train):
        x_tr = X_train.iloc[train_index]
        y_tr = y_train.iloc[train_index]
        x_te = X_train.iloc[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)

对五个分类器进行整体打包
enter description here

stacking:
enter description here

对新的特征进行重组:
enter description here

为了检测stacking是否真的有效果,我们在参数相同的条件下,对新旧两个数据集进行预测。

首先是用新的数据集进行预测:
enter description here
然后用以前的数据集进行预测:
enter description here
enter description here

出了SVC,其他四个都是惨败。
enter description here

我们再来一遍:
首先是新的数据集:
enter description here
然后是原来的数据集:
enter description here
enter description here

我们可以看到,SVC在之后的预测中准确率大幅提升,这显然说明了新增加的特征是有用的。但是我们在数据整合的阶段并没有充分考虑各个学习器的预测率有着很大的不同,所以最后导致新融合的模型不稳定。
解决方法就是在整合的时候加入权重,这个权重就是各个学习器的准确率

但是结果显示,似乎并没有多少效果提升。
这一次,我们将SVM移除,用4折交叉运算。
enter description here
从图中我们可以看到,即使在去处了准确率比较低的SVM之后,准确率的提升也不是很明显,甚至还有点下降。
但是SVM的准确率却从0.89提升到了0.95
这说明stacking的方法是有用处的。

而且从KNN每次分类的准确率都是1.0可以看出,这个模型是线性可分的,不应该作为一个比赛用的数据集。

总结:本次实验中,我并没有做过多的参数优化和特征工程。,但我所采用的方法都是一些基础中的基础,要想对一个线性不可分的模型进行建模,那还需要更进一步的技巧和相关领域的思考和理解。

最后,祝你身体健康,再见。

posted on 2018-05-26 16:24  纳兰闰土  阅读(692)  评论(0编辑  收藏  举报

导航