1 决策树
决策树:
- 是⼀种树形结构,本质是⼀颗由多个判断节点组成的树
- 其中每个内部节点表示⼀个属性上的判断,
- 每个分⽀代表⼀个判断结果的输出,
- 最后每个叶节点代表⼀种分类结果。
1.1 决策树分类原理
1.1.1 熵
物理学上,熵 Entropy 是“混乱”程度的量度。
“信息熵” (information entropy)是度量样本集合纯度最常⽤的⼀种指标。
假定当前样本集合 D 中第 k 类样本所占的⽐例为 p (k = 1, 2,. . . , |y|) ,
p = , D为样本的所有数量,C 为第k类样本的数量。
则 D的信息熵定义为((log是以2为底,lg是以10为底):
Ent(D) 的值越⼩,则 D 的纯度越高
1.1.2 决策树的划分依据⼀----信息增益
信息增益:
以某特征划分数据集前后的熵的差值。熵可以表示样本集合的不确定性,熵越⼤,样本的不确定性就越⼤。
因此可以使⽤划分前后集合熵的差值来衡量使⽤当前特征对于样本 集合D划分效果的好坏。
信息增益 = entroy(前) - entroy(后)
假定离散属性a有 V 个可能的取值:
若使⽤a来对样本集 D 进⾏划分,则会产⽣ V 个分⽀结点,
其中第v个分⽀结点包含了 D 中所有在属性a上取值为a 的样本,记为D . 我们可根据前⾯给出的信息熵公式计算出D
的信息熵,再考虑到不同的分⽀结点所包含的样本数不同,给分⽀结点赋予权重
即样本数越多的分⽀结点的影响越⼤,于是可计算出⽤属性a对样本集 D 进⾏划分所获得的"信息增益" (information
gain)
其中:
特征a对训练数据集D的信息增益Gain(D,a),定义为集合D的信息熵Ent(D)与给定特征a条件下D的信息条件熵Ent(D∣a)之
差,即公式为:
D-v 表示a属性中第v个分⽀节点包含的样本数
C-kv 表示a属性中第v个分⽀节点包含的样本数中,第k个类别下包含的样本数
⼀般⽽⾔,信息增益越⼤,则意味着使⽤属性 a 来进⾏划分所获得的"纯度提升"越⼤。因此,我们可⽤信息增益来进⾏
决策树的划分属性选择,
1.1.3 决策树的划分依据⼆----信息增益率
信息增益率:增益率是⽤前⾯的信息增益Gain(D, a)和属性a对应的"固有值"
其中:
1.1.4 决策树的划分依据三 ----基尼值和基尼指数
基尼值Gini(D):从数据集D中随机抽取两个样本,其类别标记不⼀致的概率。故,Gini(D)值越⼩,数据集D的纯
度越⾼。
其中:
小结:
决策树变量的两种类型:
- 数字型(Numeric):变量类型是整数或浮点数,如前⾯例⼦中的“年收⼊”。⽤“>=”,“>”,“<”或“<=”作为分割条件
(排序后,利⽤已有的分割情况,可以优化分割算法的时间复杂度)。 - 名称型(Nominal):类似编程语⾔中的枚举类型,变量只能从有限的选项中选取,⽐如前⾯例⼦中的“婚姻情
况”,只能是“单身”,“已婚”或“离婚”,使⽤“=”来分割。
如果⼀个分割点可以将当前的所有节点分为两类,使得每⼀类都很“纯”,也就是同⼀类的记录较多,那么就是⼀个好分
割点。
1.2 cart剪枝
1.2.1 问什么要进行cart剪枝
在决策树学习中,为了尽可能正确分类训练样本,结点划分过程将不断重复,有时会造成决策树分⽀过多,这时就可能
因训练样本学得"太好"了,以致于把训练集⾃身的⼀些特点当作所有数据都具有的⼀般性质⽽导致过拟合。因此,可通
过主动去掉⼀些分⽀来降低过拟合的⻛险。
1.2.2 常⽤的减枝⽅法
1.2.2.1 预剪枝
预剪枝是指在决策树⽣成过程中,对每个结点在划分前先进⾏估计,若当前结点的划分不能带来决策树泛化性能提
升,则停⽌划分并将当前结点标记为叶结点;
1.2.2.2 后剪枝
后剪枝则是先从训练集⽣成⼀棵完整的决策树,然后⾃底向上地对⾮叶结点进⾏考察,若将该结点对应的⼦树替换
为叶结点能带来决策树泛化性能提升,则将该⼦树替换为叶结点。
1.3 特征工程-特征提取
1.3.1 定义
将任意数据(如⽂本或图像)转换为可⽤于机器学习的数字特征
- 特征提取分类:
- 字典特征提取(特征离散化)
- ⽂本特征提取
- 图像特征提取(深度学习将介绍)
1.3.2 字典特征提取
- klearn.feature_extraction.DictVectorizer(sparse=True,…)
- DictVectorizer.fit_transform(X)
- X:字典或者包含字典的迭代器返回值
- 返回sparse矩阵
- DictVectorizer.get_feature_names() 返回类别名称
- DictVectorizer.fit_transform(X)
Ex:
1.3.3 文本特征提取
- sklearn.feature_extraction.text.CountVectorizer(stop_words=[])
- 返回词频矩阵
- CountVectorizer.fit_transform(X)
- X:⽂本或者包含⽂本字符串的可迭代对象
- 返回值:返回sparse矩阵
- CountVectorizer.get_feature_names() 返回值:单词列表
- sklearn.feature_extraction.text.TfidfVectorizer
我们对以下数据进⾏特征提取
["life is short,i like python",
"life is too long,i dislike python"]
如果是中文的我们需要先使用 jieba对字符串进行处理
["⼀种还是⼀种今天很残酷,明天更残酷,后天很美好,但绝对⼤部分是死在明天晚上,所以每个⼈不要放弃今天。",
"我们看到的从很远星系来的光是在⼏百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
"如果只⽤⼀种⽅式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]
['⼀种 还是 ⼀种 今天 很 残酷 , 明天 更 残酷 , 后天 很 美好 , 但 绝对 ⼤部分 是 死 在 明天 晚上 , 所以 每个 ⼈ 不要 放弃 今
天 。', '我们 看到 的 从 很 远 星系 来 的 光是在 ⼏百万年 之前 发出 的 , 这样 当 我们 看到 宇宙 时 , 我们 是 在 看 它 的 过去
。', '如果 只⽤ ⼀种 ⽅式 了解 某样 事物 , 你 就 不会 真正 了解 它 。 了解 事物 真正 含义 的 秘密 取决于 如何 将 其 与 我们
所 了解 的 事物 相 联系 。']
from sklearn.feature_extraction.text import CountVectorizer
import jieba
data = ["⼀种还是⼀种今天很残酷,明天更残酷,后天很美好,但绝对⼤部分是死在明天晚上,所以每个⼈不要放弃今天。",
"我们看到的从很远星系来的光是在⼏百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
"如果只⽤⼀种⽅式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]
# data = " ".join(list(jieba.cut("⼀种还是⼀种今天很残酷,明天更残酷,后天很美好,但绝对⼤部分是死在明天晚上,所以每个⼈不要放弃今天。")))
#
#
# ## jieba 只能对字符串进行分割 (参数要传字符串)
def cut_text(text):
data = " ".join(list(jieba.cut(text)))
return data
text_list=[]
for strr in data :
text_list.append(cut_text(strr))
# print(text_list)
transfer = CountVectorizer()
new_text = transfer.fit_transform(text_list)
print(new_text)
print(new_text.toarray())
print(transfer.get_feature_names())
1.3.4 Tf-idf⽂本特征提取
- TF-IDF的主要思想是:如果某个词或短语在⼀篇⽂章中出现的概率⾼,并且在其他⽂章中很少出现,则认为此词或
者短语具有很好的类别区分能⼒,适合⽤来分类。 - TF-IDF作⽤:⽤以评估⼀字词对于⼀个⽂件集或⼀个语料库中的其中⼀份⽂件的重要程度。
公式:
- 词频(term frequency,tf)指的是某⼀个给定的词语在该⽂件中出现的频率
- 逆向⽂档频率(inverse document frequency,idf)是⼀个词语普遍重要性的度量。某⼀特定词语的idf,可以由总
⽂件数⽬除以包含该词语之⽂件的数⽬,再将得到的商取以10为底的对数得到
Ex:
假如⼀篇⽂章的总词语数是100个,⽽词语"⾮常"出现了5次,那么"⾮常"⼀词在该⽂件中的词频就是5/100=0.05。
⽽计算⽂件频率(IDF)的⽅法是以⽂件集的⽂件总数,除以出现"⾮常"⼀词的⽂件数。
所以,如果"⾮常"⼀词在1,0000份⽂件出现过,⽽⽂件总数是10,000,000份的话,
其逆向⽂件频率就是lg(10,000,000 / 1,0000)=3。
最后"⾮常"对于这篇⽂档的tf-idf的分数为0.05 * 3=0.15
1.4 决策树算法api
- class sklearn.tree.DecisionTreeClassifier(criterion=’gini’, max_depth=None,random_state=None)
- criterion
- 特征选择标准
- “gini"或者"entropy”,前者代表基尼系数,后者代表信息增益。⼀默认"gini",即CART算法。
- min_samples_split
- 内部节点再划分所需最⼩样本数
- 这个值限制了⼦树继续划分的条件,如果某节点的样本数少于min_samples_split,则不会继续再尝试选择
最优特征来进⾏划分。 默认是2.如果样本量不⼤,不需要管这个值。如果样本量数量级⾮常⼤,则推荐增
⼤这个值。我之前的⼀个项⽬例⼦,有⼤概10万样本,建⽴决策树时,我选择了min_samples_split=10。
可以作为参考。
- min_samples_leaf
- 叶⼦节点最少样本数
- 这个值限制了叶⼦节点最少的样本数,如果某叶⼦节点数⽬⼩于样本数,则会和兄弟节点⼀起被剪枝。
默认是1,可以输⼊最少的样本数的整数,或者最少样本数占样本总数的百分⽐。如果样本量不⼤,不需要
管这个值。如果样本量数量级⾮常⼤,则推荐增⼤这个值。之前的10万样本项⽬使⽤min_samples_leaf的
值为5,仅供参考。
- max_depth
- 决策树最⼤深度
- 决策树的最⼤深度,默认可以不输⼊,如果不输⼊的话,决策树在建⽴⼦树的时候不会限制⼦树的深度。
⼀般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制
这个最⼤深度,具体的取值取决于数据的分布。常⽤的可以取值10-100之间
- random_state
- 随机数种⼦
- criterion
1.5 泰坦尼克号案例
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer
from sklearn.tree import DecisionTreeClassifier,export_graphviz
# 1.获取数据
# 2.数据基本处理
# 2.1 确定特征值,⽬标值
# 2.2 缺失值处理
# 2.3 数据集划分
# 3.特征⼯程(字典特征抽取)
# 4.机器学习(决策树)
# 5.模型评估
# 获取数据
data = pd.read_csv("http://biostat.mc.vanderbilt.edu/wiki/pub/Main/DataSets/titanic.txt")
#确定目标值、特征值
x = data[['pclass','age','sex']]
y = data['survived']
#缺失值处理
data['age'].fillna(data['age'].mean(),inplace=True)
#数据集分割
x_train,x_test,y_train,y_test = train_test_split(x,y,random_state=22,test_size=0.2)
#特征工程-字典特征提取
x_train=x_train.to_dict(orient='records')
x_test = x_test.to_dict(orient='records')
transfer = DictVectorizer(sparse=False)
x_train = transfer.fit_transform(x_train)
x_test = transfer.fit_transform(x_test)
#机器学习(决策树)
estimator = DecisionTreeClassifier( criterion = 'entropy' , max_depth=5)
estimator.fit(x_train,y_train)
estimator.score(x_test,y_test)
export_graphviz(estimator,out_file='tree.dot',feature_names=['age', 'pclass=1st', 'pclass=2nd', 'pclass=3rd', '⼥性', '男性'])
### 随机森林
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier()
from sklearn.model_selection import GridSearchCV
param = {"n_estimators":[100,120,200],'max_depth':[3,7,11]}
gc = GridSearchCV(rf , param_grid=param,cv = 3)
gc.fit(x_train,y_train)
score = gc.score(x_test,y_test)
print(score)
1.6 决策树可视化
- sklearn.tree.export_graphviz() 该函数能够导出DOT格式
- tree.export_graphviz(estimator,out_file='tree.dot’,feature_names=[‘’,’’])
export_graphviz(estimator, out_file="./data/tree.dot", feature_names=['age', 'pclass=1st', 'pclass=2nd', 'pclas
s=3rd', '⼥性', '男性'])
Dot文件中的内容
把文件中的内容复制到下面的网站中就可以显示决策树的结构了
http://webgraphviz.com/
1.7回归决策树
假如我们有n个特征,每个特征有s (i ∈ (1, n))个取值,那我们遍历所有特征,
尝试该特征所有取值,对空间进⾏划分,直到取到特征 j 的取值 s,使得损失函数最⼩,这样就得到了⼀个划分点。
算法描述:
为了易于理解,接下来通过⼀个简单实例加深对回归决策树的理解。
训练数据⻅下表,⽬标是得到⼀棵最⼩⼆乘回归树。
(1)选择最优的切分特征j与最优切分点s:
- 确定第⼀个问题:选择最优切分特征:
- 在本数据集中,只有⼀个特征,因此最优切分特征⾃然是x。
- 确定第⼆个问题:我们考虑9个切分点 [1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5] 。
-
a、计算⼦区域输出值:
例如,取 s=1.5。此时R1 = 1, R2 = 2, 3, 4, 5, 6, 7, 8, 9, 10,这两个区域的输出值分别为:- c1 = 5.56
- c2 = (5.7 + 5.91 + 6.4 + 6.8 + 7.05 + 8.9 + 8.7 + 9 + 9.05)/9 = 7.50。
同理,得到其他各切分点的⼦区域输出值,如下表:
b、计算损失函数值,找到最优切分点:
把c1, c2的值代⼊到同平⽅损失函数Loss(y, f(x)) = (f(x) − y) ,
当s=1.5时,
同理,计算得到其他各切分点的损失函数值,可获得下表:
显然取 s=6.5时,m(s)最⼩。因此,第⼀个划分变量【j=x,s=6.5】
(2)⽤选定的(j,s)划分区域,并决定输出值
- 两个区域分别是:R1 = {1, 2, 3, 4, 5, 6}, R2 = {7, 8, 9, 10}
- 输出值c = avg(yi∣xi ∈ Rm), c1 = 6.24, c2 = 8.91
3)调⽤步骤 (1)、(2),继续划分:
2. 集成学习
集成学习通过建⽴⼏个模型来解决单⼀预测问题。它的⼯作原理是⽣成多个分类器/模型,各⾃独⽴地学习和作出预
测。这些预测最后结合成组合预测,因此优于任何⼀个单分类的做出预测。
2.1 集成学习中boosting和Bagging
2.2 Bagging集成原理
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/5e4fe526d9e54e898afacd4fa30eeb4d.png
2.3 随机森林构造过程
在机器学习中,随机森林是⼀个包含多个决策树的分类器,并且其输出的类别是由个别树输出的类别的众数⽽定。
随机森林 = Bagging + 决策树
2.4 包外估计 (Out-of-Bag Estimate)定义
随机森林的 Bagging 过程,对于每⼀颗训练出的决策树 g ,与数据集 D 有如下关系:
对于星号的部分,即是没有选择到的数据,称之为 Out-of-bag(OOB)数据,当数据⾜够多,对于任意⼀组数据 (x , y )
是包外数据的概率为:
由于基分类器是构建在训练样本的⾃助抽样集上的,只有约 63.2% 原样本集出现在中,⽽剩余的 36.8% 的数据作为包
外数据,可以⽤于基分类器的验证集。
包外估计用途:
当基学习器是决策树时,可使⽤包外样本来辅助剪枝 ,或⽤于估计决策树中各结点的后验概率以辅助对零训练样
本结点的处理;
当基学习器是神经⽹络时,可使⽤包外样本来辅助早期停⽌以减⼩过拟合 。
2.5 bagging集成优点
Bagging + 决策树/线性回归/逻辑回归/深度学习… = bagging集成学习⽅法
经过上⾯⽅式组成的集成学习⽅法:
- 均可在原有算法上提⾼约2%左右的泛化正确率
- 简单, ⽅便, 通⽤
2.6 Boosting
2.6.1 什么是boosting
随着学习的积累从弱到强
简⽽⾔之:每新加⼊⼀个弱学习器,整体能⼒就会得到提升
2.6.2 bagging集成与boosting集成的区别:
- 区别⼀:数据⽅⾯
- Bagging:对数据进⾏采样训练;
- Boosting:根据前⼀轮学习结果调整数据的重要性。
- 区别⼆:投票⽅⾯
- Bagging:所有学习器平权投票;
- Boosting:对学习器进⾏加权投票。
- 区别三:学习顺序
- Bagging的学习是并⾏的,每个学习器没有依赖关系;
- Boosting学习是串⾏,学习有先后顺序。
- 区别四:主要作⽤
- Bagging主要⽤于提⾼泛化性能(解决过拟合,也可以说降低⽅差)
- Boosting主要⽤于提⾼训练精度 (解决⽋拟合,也可以说降低偏差)
2.7 AdaBoost介绍
构造过程细节
- 步骤⼀:初始化训练数据权重相等,训练第⼀个学习器。
- 步骤⼆:AdaBoost反复学习基本分类器,在每⼀轮m = 1, 2, …, M顺次的执⾏下列操作:
- (a) 在权值分布为D 的训练数据上,确定基分类器;
(b) 计算该学习器在训练数据中的错误率:
(c) 计算该学习器的投票权重:
(d) 根据投票权重,对训练数据重新赋权
重复执⾏a到d步,m次;
- 步骤三:对m个学习器进⾏加权投票