前言:前面已经介绍了的几种算法,应该对算法有了一个基本的认识了,本章主要是在前面已经学到的基础上,对前面的算法模型进行整合操作,训练出效果更好的分类器模型。
集成学习
集成学习的思想是将若干个学习器(分类器&回归器)组合之后产生一个新学习器。弱分类器( weak learner)指那些分类准确率只稍微好于随机猜测的分类器( errorrate<0.5);集成算法的成功在于保证弱分类器的多样性( Diversity)。而且集成不稳定的算法也能够得到一个比较明显的性能提升。
常见的集成学习思想有:
(1)投票选举(bagging: 自举汇聚法 bootstrap aggregating): 是基于数据随机重抽样分类器构造的方法
(2)再学习(boosting): 是基于所有分类器的加权求和的方法
对于不同的数据进行不同的集成算法的构建,大致来说可以分为以下四种情况:
(1)弱分类器间存在一定的差异性,这会导致分类的边界不同,也就是说可能存在错误。那么将多个弱分类器合并后,就可以得到更加合理的边界,减少整体的错率,实现更好的效果;
(2)对于数据集过大或者过小,可以分别进行划分和有放回的操作产生不同的数据子集,然后使用数据子集训练不同的分类器,最终再合并成为一个大的分类器;
(3)如果数据的划分边界过于复杂,使用线性模型很难描述情况,那么可以训练多个模型,然后再进行模型的融合;
(4)对于多个异构的特征集的时候,很难进行融合,那么可以考虑每个数据集构建一个分类模型,然后将多个模型融合。
例如下图,是构建三个不同的分类器,在做一个合并。
随机森林
随机森林是在 Bagging策略的基础上进行修改后的一种算法。那随机森林具体如何构建呢?,所谓的随机森林,重点要理解“随机”这两个关键字,表现为以下两个方面:
(1)数据的随机性化
(2)待选特征的随机化
使得随机森林中的决策树都能够彼此不同,提升系统的多样性,从而提升分类性能。数据的随机化:使得随机森林中的决策树更普遍化一点,适合更多的场景。
构建流程
采取有放回的抽样方式 构造子数据集,保证不同子集之间的数量级一样(不同子集/同一子集 之间的元素可以重复)
利用子数据集来构建子决策树,将这个数据放到每个子决策树中,每个子决策树输出一个结果。
然后统计子决策树的投票结果,得到最终的分类 就是 随机森林的输出结果。
具体构建过程如下:
(1)从样本集中用 Bootstrap采样选出n个样本;
(2)从所有属性中随机选择K个属性,选择出最佳分割属性作为节点创建决策树
(3)重复以上两步m次,即建立m棵决策树
(4)这m个决策树形成随机森林,通过投票表决结果决定数据属于那一类
注意:(有放回的准确率在:70% 以上, 无放回的准确率在:60% 以上)
如下图,假设随机森林中有3棵子决策树,2棵子树的分类结果是A类,1棵子树的分类结果是B类,那么随机森林的分类结果就是A类。
待选特征的随机化过程
(1)子树从所有的待选特征中随机选取一定的特征。
(2)在选取的特征中选取最优的特征。
下图中,蓝色的方块代表所有可以被选择的特征,也就是目前的待选特征;黄色的方块是分裂特征。 左边是一棵决策树的特征选取过程,通过在待选特征中选取最优的分裂特征完成分裂。 右边是一个随机森林中的子树的特征选取过程。
随机森林推广算法
算法总结
RF的主要优点
1.训练可以并行化,对于大规模样本的训练具有速度的优势;
2.由于进行随机选择决策树划分特征列表,这样在样本维度比较高的时候,仍然具有比较高的训练性能;
3.给以给出各个特征的重要性列表;
4.由于存在随机抽样,训练出来的模型方差小,泛化能力强;
5.RF实现简单;
6.对于部分特征的缺失不敏感。
RF的主要缺点:
1..在某些噪音比较大的特征上,RF模型容易陷入过拟;
2.取值比较多的划分特征对RF的决策会产生更大的影响,从而有可能影响模型的效果;
示例:乳腺癌预测
在现实生活中,机器学习的应用非常广泛,在医学方面也发挥着非常重要的作用,下面就以一个宫颈癌预测的例子来简要说明一下随机森林算法的思想。
比如,小明的妈妈感觉身体非常不好,医生通过询问和调查,收集和小明妈妈的很多数据,比如年龄,工作,是否抽烟等等,把这些数据输入计算机,计算机就会给一个患有某种病的概率,医生则可以根据这个概率做出疾病的最终结果,例如把这些数据输入一个患有乳腺癌的模型,可如何构建这个模型呢?这是我们应该关注的问题。构建此模型的步骤如下:
首先收集数据
这是最基础也是最重要的过程,为了方便,我们直接下载权威结构公开的数据:
下载的地址如下:http://archive.ics.uci.edu/ml/datasets/Cervical+cancer+(Risk+Factors)
然后观察目标属性和特征特征属性如下:
u'Age', u'Number of sexual partners', u'First sexual intercourse', u'Num of pregnancies', u'Smokes', u'Smokes (years)', u'Smokes (packs/year)', u'Hormonal Contraceptives', u'Hormonal Contraceptives (years)', u'IUD', u'IUD (years)', u'STDs', u'STDs (number)', u'STDs:condylomatosis', u'STDs:cervical condylomatosis', u'STDs:vaginal condylomatosis', u'STDs:vulvo-perineal condylomatosis', u'STDs:syphilis', u'STDs:pelvic inflammatory disease', u'STDs:genital herpes', u'STDs:molluscum contagiosum', u'STDs:AIDS', u'STDs:HIV', u'STDs:Hepatitis B', u'STDs:HPV', u'STDs: Number of diagnosis', u'STDs: Time since first diagnosis', u'STDs: Time since last diagnosis', u'Dx:Cancer', u'Dx:CIN', u'Dx:HPV', u'Dx', u'Hinselmann', u'Schiller', u'Citology', u'Biopsy'
最后就是建立模型,建立模型的步骤如下:
- 导入模块。
#导入我们要用的包,包括算法数据导入模块,算法评估模块,算法模块,以及画图模块。
最后要画roc和auc曲线图,因而导入相应的画图包。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn import tree
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler,Imputer,LabelBinarizer
from sklearn import metrics#参数,roc和auc
from sklearn.preprocessing import label_binarize#二值化
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False
- 导入数据
#这里的导入数据就是导入刚刚下载的数据
names = [u'Age', u'Number of sexual partners', u'First sexual intercourse',
u'Num of pregnancies', u'Smokes', u'Smokes (years)',
u'Smokes (packs/year)', u'Hormonal Contraceptives',
u'Hormonal Contraceptives (years)', u'IUD', u'IUD (years)', u'STDs',
u'STDs (number)', u'STDs:condylomatosis',
u'STDs:cervical condylomatosis', u'STDs:vaginal condylomatosis',
u'STDs:vulvo-perineal condylomatosis', u'STDs:syphilis',
u'STDs:pelvic inflammatory disease', u'STDs:genital herpes',
u'STDs:molluscum contagiosum', u'STDs:AIDS', u'STDs:HIV',
u'STDs:Hepatitis B', u'STDs:HPV', u'STDs: Number of diagnosis',
u'STDs: Time since first diagnosis', u'STDs: Time since last diagnosis',
u'Dx:Cancer', u'Dx:CIN', u'Dx:HPV', u'Dx', u'Hinselmann', u'Schiller',
u'Citology', u'Biopsy']#df.columns
path="datas/risk_factors_cervical_cancer.csv"
df = pd.read_csv(path)
print(df.shape)
查看数据,查看一下总的数据
print(df.shape)
输出结果如下:
(858, 36)
- 建划分数据集
#.划分测试集合训练集
x=df.iloc[:,0:-4]
y=df.iloc[:,-4:]
x=x.replace("?", np.NAN)
#通过平局值来替换nan
imputer=Imputer(missing_values="NaN")
x=imputer.fit_transform(x,y)
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=0)
print("训练样本数量:%d,特征属性数目:%d,目标属性数目:%d"%(x_train.shape[0],x_train.shape[1],y_train.shape[1]))
输出的结果如下:
训练样本数量:686,特征属性数目:32,目标属性数目:4
- 模型构建和预测:
ss = MinMaxScaler()
x_train = ss.fit_transform(x_train)
x_test = ss.transform(x_test)
rf = RandomForestClassifier(n_estimators=50,criterion="gini",max_depth=1,random_state=10)
rf.fit(x_train,y_train)
score = rf.score(x_test,y_test)
- 模型的评估
print("准确率:%.2f%%"%(score*100))
forest_y_score = rf.predict_proba(x_test)
# print(forest_y_score)
#计算roc和auc
forest_fpr1, forest_tpr1, _ = metrics.roc_curve(label_binarize(y_test[names[-4]],classes=(0,1,2)).T[0:-1].T.ravel(), forest_y_score[0].ravel())
forest_fpr2, forest_tpr2, _ = metrics.roc_curve(label_binarize(y_test[names[-3]],classes=(0,1,2)).T[0:-1].T.ravel(), forest_y_score[1].ravel())
forest_fpr3, forest_tpr3, _ = metrics.roc_curve(label_binarize(y_test[names[-2]],classes=(0,1,2)).T[0:-1].T.ravel(), forest_y_score[2].ravel())
forest_fpr4, forest_tpr4, _ = metrics.roc_curve(label_binarize(y_test[names[-1]],classes=(0,1,2)).T[0:-1].T.ravel(), forest_y_score[3].ravel())
#AUC值
auc1 = metrics.auc(forest_fpr1, forest_tpr1)
auc2 = metrics.auc(forest_fpr2, forest_tpr2)
auc3 = metrics.auc(forest_fpr3, forest_tpr3)
auc4 = metrics.auc(forest_fpr4, forest_tpr4)
print ("Hinselmann目标属性AUC值:", auc1)
print ("Schiller目标属性AUC值:", auc2)
print ("Citology目标属性AUC值:", auc3)
print ("Biopsy目标属性AUC值:", auc4)
输出的结果为:
准确率:89.53%
Hinselmann目标属性AUC值: 0.984586262844781
Schiller目标属性AUC值: 0.9629867495943752
Citology目标属性AUC值: 0.9453082747431043
Biopsy目标属性AUC值: 0.9642712276906437
- 画auc曲线
plt.figure(figsize=(8, 6), facecolor='w')
plt.plot(forest_fpr1,forest_tpr1,c='r',lw=2,label=u'Hinselmann目标属性,AUC=%.3f' % auc1)
plt.plot(forest_fpr2,forest_tpr2,c='b',lw=2,label=u'Schiller目标属性,AUC=%.3f' % auc2)
plt.plot(forest_fpr3,forest_tpr3,c='g',lw=2,label=u'Citology目标属性,AUC=%.3f' % auc3)
plt.plot(forest_fpr4,forest_tpr4,c='y',lw=2,label=u'Biopsy目标属性,AUC=%.3f' % auc4)
plt.plot((0,1),(0,1),c='#a0a0a0',lw=2,ls='--')
plt.xlim(-0.001, 1.001)
plt.ylim(-0.001, 1.001)
plt.xticks(np.arange(0, 1.1, 0.1))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.xlabel('False Positive Rate(FPR)', fontsize=16)
plt.ylabel('True Positive Rate(TPR)', fontsize=16)
plt.grid(b=True, ls=':')
plt.legend(loc='lower right', fancybox=True, framealpha=0.8, fontsize=12)
plt.title(u'随机森林多目标属性分类ROC曲线', fontsize=18)
plt.show()
结果如下图所示:
分析:由于目标属性含有多个,在进行评估的时候应该考虑多个目标属性的影响,从上图看出,模型的整体效果还是挺不错的。
7.比较不同树的数量和不同深度下对模型的影响
# 比较不同树数目、树最大深度的情况下随机森林的正确率
# 一般情况下,初始的随机森林树个数是100,深度1,如果需要我们再进行优化操作
x_train2, x_test2, y_train2, y_test2 = train_test_split(x,y, test_size=0.5, random_state=0)
print("训练样本数量%d,测试样本数量:%d" % (x_train2.shape[0], x_test2.shape[0]))
## 比较
estimators = [1, 50, 100, 500]
depth = [1, 2, 3, 7, 15]
err_list = []
for es in estimators:
es_list = []
for d in depth:
tf = RandomForestClassifier(n_estimators=es, criterion='gini', max_depth=d, max_features=None,
random_state=0)
tf.fit(x_train2, y_train2)
st = tf.score(x_test2, y_test2)
err = 1 - st
es_list.append(err)
print("%d决策树数目,%d最大深度,正确率:%.2f%%" % (es, d, st * 100))
err_list.append(es_list)
## 画图
plt.figure(facecolor='w')
i = 0
colors = ['r', 'b', 'g', 'y']
lw = [1, 2, 4, 3]
max_err = 0
min_err = 100
for es, l in zip(estimators, err_list):
plt.plot(depth, l, c=colors[i], lw=lw[i], label=u'树数目:%d' % es)
max_err = max((max(l), max_err))
min_err = min((min(l), min_err))
i += 1
plt.xlabel(u'树深度', fontsize=16)
plt.ylabel(u'错误率', fontsize=16)
plt.legend(loc='upper left', fancybox=True, framealpha=0.8, fontsize=12)
plt.grid(True)
plt.xlim(min(depth), max(depth))
plt.ylim(min_err * 0.99, max_err * 1.01)
plt.title(u'随机森林中树数目、深度和错误率的关系图', fontsize=18)
plt.show()
得到的结果如下: