目录
混淆矩阵
混淆矩阵(Confusion Matrix),它的本质远没有它的名字听上去那么拉风。
矩阵,可以理解为就是一张表格,混淆矩阵其实就是一张表格而已。 以分类模型中最简单的二分类为例,对于这种问题,我们的模型最终需要判断样本的结果是0还是1,或者说是positive还是negative。
我们通过样本的采集,能够直接知道真实情况下,哪些数据结果是positive,哪些结果是negative。同时,我们通过用样本数据跑出分类型模型的结果,也可以知道模型认为这些数据哪些是positive,哪些是negative。
因此,我们就能得到这样四个基础指标,我称他们是一级指标(最底层的)
- 真实值是positive,模型认为是positive的数量(True Positive=TP) 真正类。样本的真实类别是正类,并且模型识别的结果也是正类。
- 真实值是positive,模型认为是negative的数量(False Negative=FN)假负类。样本的真实类别是正类,但是模型将其识别为负类。
- 真实值是negative,模型认为是positive的数量(False Positive=FP)假正类。样本的真实类别是负类,但是模型将其识别为正类。
- 真实值是negative,模型认为是negative的数量(True Negative=TN) 真负类。样本的真实类别是负类,并且模型将其识别为负类
将这四个指标一起呈现在表格中,就能得到如下这样一个矩阵,我们称它为混淆矩阵(Confusion Matrix):
混淆矩阵的指标
预测性分类模型,肯定是希望越准越好。那么,对应到混淆矩阵中,那肯定是希望TP与TN的数量大,而FP与FN的数量小。所以当我们得到了模型的混淆矩阵后,就需要去看有多少观测值在第二、四象限对应的位置,这里的数值越多越好;反之,在第一、三四象限对应位置出现的观测值肯定是越少越好。
二级指标 但是,混淆矩阵里面统计的是个数,有时候面对大量的数据,光凭算个数,很难衡量模型的优劣。因此混淆矩阵在基本的统计结果上又延伸了如下4个指标,我称他们是二级指标(通过最底层指标加减乘除得到的):
-
准确率(Accuracy)—— 针对整个模型
-
精确率(Precision)
-
灵敏度(Sensitivity):就是召回率(Recall)
-
特异度(Specificity)
三级指标 这个指标叫做F1 Score。他的计算公式是:
F1-Score指标综合了Precision与Recall的产出的结果。F1-Score的取值范围从0到1的,1代表模型的输出最好,0代表模型的输出结果最差。
混淆矩阵的实例
当分类问题是二分问题是,混淆矩阵可以用上面的方法计算。当分类的结果多于两种的时候,混淆矩阵同时适用。
一下面的混淆矩阵为例,我们的模型目的是为了预测样本是什么动物(三种动物 猫狗猪),这是我们的结果:
通过混淆矩阵,我们可以得到如下结论:
Accuracy
在总共66个动物中,我们一共预测对了10 + 15 + 20=45个样本,所以准确率(Accuracy)=45/66 = 68.2%。
以猫为例,我们可以将上面的图合并为二分问题:
Precision
所以,以猫为例,模型的结果告诉我们,66只动物里有13只是猫,但是其实这13只猫只有10只预测对了。模型认为是猫的13只动物里,有1条狗,两只猪。所以,Precision(猫)= 10/13 = 76.9%
Recall 灵敏度 查全率
以猫为例,在总共18只真猫中,我们的模型认为里面只有10只是猫,剩下的3只是狗,5只都是猪。这5只八成是橘猫,能理解。所以,Recall(猫)= 10/18 = 55.6%
Specificity
以猫为例,在总共48只不是猫的动物中,模型认为有45只不是猫。所以,Specificity(猫)= 45/48 = 93.8%。
虽然在45只动物里,模型依然认为错判了6只狗与4只猫,但是从猫的角度而言,模型的判断是没有错的。
(这里是参见了Wikipedia,Confusion Matrix的解释,https://en.wikipedia.org/wiki/Confusion_matrix)
F1-Score
通过公式,可以计算出,对猫而言,F1-Score=(2 * 0.769 * 0.556)/( 0.769 + 0.556) = 64.54%
决策树理论:
决策树是如何工作的
决策树(Decision Tree)是一种非参数的有监督学习方法,它能够从一系列有特征和标签的数据中总结出决策规则,并用树状图的结构来呈现这些规则,以解决分类和回归问题。
决策树算法容易理解,适用各种数据,在解决各 种问题时都有良好表现,尤其是以树模型为核心的各种集成算法,在各个行业和领域都有广泛的应用。
我们来简单了解一下决策树是如何工作的。决策树算法的本质是一种图结构,我们只需要问一系列问题就可以对数 据进行分类了。比如说,来看看下面这组数据集,这是一系列西瓜挑选的样本数据。
CodeMarkdown
目标: 将西瓜分为好瓜和坏瓜。那根据已经收集到的数据,决策树算法为我们算出了下面的 这棵决策树
假如我们现在发现了一钟西瓜,它是纹理清晰,根蔕稍微蜷曲,色泽青绿,我们就可以通过这棵决策 树来判断它的所属类别。
可以看出,在这个决策过程中,我们一直在对记录的特征进行提问。
最初的问题所在的地方叫做根节点,在得到结论前的每一个问题都是中间节点,而得到的每一个结论(动物的类别)都叫做叶子节点。
数据结构的概念:节点
- 根节点:没有进边,有出边。包含最初的,针对特征的提问。
- 中间节点:既有进边也有出边,进边只有一条,出边可以有很多条。都是针对特征的提问。
- 叶子节点:有进边,没有出边,每个叶子节点都是一个类别标签。
- 子节点和父节点:在两个相连的节点中,更接近根节点的是父节点,另一个是子节点。
决策树是机器学习的一类常见算法,其核心思想是根据训练数据集,构建一个树状模型来对新样本进行预测。
总结:
- 决策树的结果:类似一棵倒置的树。
- 一般来说,一颗决策树包含一个根结点、若干内部结点和若干个叶结点;
- 树的叶结点是预测结果,而所有非叶结点皆是一个个决策过程,其它每个内部结点(包括根结点)则对应一个属性测试。
- 决策树根据内部结点的属性测试结果将该结点所包含的样本集按照属性测试的结果被划分到不同的子结点中。
- 这是一种简单且直观的“分而治之”(divide-and-conquer)策略,决策树学习的目的是为了产生一颗泛化能力强的决策树。
生成决策树时解决的问题:
- (1)如何选择测试条件进行划分
- (2)什么情况下可以选择结束划分
希望:
划分后,划分的子集能够显得更“纯”,即划分后的任意一个子集都尽可能的属于同一类别。
决策树生长过程
虽然,在决策树生长过程中,对于数据集合的每一次划分,应该选择可以令子集纯度更高的划分条件。而随着数据集合不断被划分,子集的纯度越来越高,至到该节点下的样本都属于同一个类别。那么什么时候停止划分呢? (1)当前节点包含的样本全属于同一类别,无需划分; (2)当前属性集为空,或是所有样本在所有属性上取值相同,无法划分;把当前结点标记为叶结点,并将其类别设定为该结点所含样本最多的类别,利用了当前结点的后验分布
决策树的分支结点所包含的样本尽可能属于同一类别,即结点的“纯度”越来越高,可以高效地从根结点到达叶结点,得到决策结果。 决策树生长过程中,重点在于其中的“纯度”计算公式,也就是选择最优特征的过程。
第一个问题需要解决纯度的计算问题,用到了信息论中的知识:信息熵,信息增益
2. 决策树分类原理
学习目标
- 知道如何求解信息熵
- 知道信息增益的求解过程
- 知道信息增益率的求解过程
- 知道基尼系数的求解过程
- 知道信息增益、信息增益率和基尼系数三者之间的区别、联系
2.1. 熵的概念
熵(Entropy)这个概念最早出现在热力学中.它的物理意思表示该体系的混乱程度,简单地说,如果该体系下的分子运动杂乱程度増加,则该体系的熵也随着增加。
在熵这个概念普及之后,1948年,信息论之父克劳德•艾尔伍德香农提出了信息熵的
概念。 类比下来,我们可以认为信息熵是用来描述信息的混乱程度或者信息的不确定度.
2.2. 信息熵的计算举例:
球队获胜的信息熵计算: Ent(D) = -(p1 * logp1 + p2 * logp2 + ... + p4 * logp4), 其中 p1, ..., p4 分别是这 4 支球队夺冠的概率。
当每支球队夺冠概率相等都是 1/4 的时:Ent(D) = -(4 * 1/4 * log1/4) = 2 每个事件概率相同时,熵最大,这件事越不确定。
有4个球队 {A,B,C,D} ,获胜概率分别为{1/2, 1/4, 1/8, 1/8} 求Ent(D)
2.3. 决策树的划分依据一----信息增益
信息增益:以某特征划分数据集前后的熵的差值。熵可以表示样本集合的不确定性,熵越大,样本的不确定性就越大。因此可以使用划分前后集合熵的差值来衡量使用当前特征对于样本集合D划分效果的好坏。
信息增益 = entroy(前) - entroy(后)
注:信息增益表示得知特征X的信息而使得类Y的信息熵减少的程度
2.4. 举例:求解划分根结点的最优划分属性
西瓜数据集上基于信息增益生成的决策树
2.5. 决策树的划分依据二----信息增益率
2.6. C4.5 信息增益率
2.7. 决策树的划分依据三 ----基尼值和基尼指数
CART 决策树使用"基尼指数" (Gini index)来选择划分属性.
CART 是Classification and Regression Tree的简称,这是一种著名的决策树学习算法,分类和回归任务都可用。
https://www.cnblogs.com/yuyingblogs/p/15320471.html
2.8. 常见决策树的启发函数比较
ID3 算法
存在的缺点
- (1)ID3算法在选择根节点和各内部节点中的分支属性时,采用信息增益作为评价标准。信息增益的缺点是倾向于选择取值较多的属性,在有些情况下这类属性可能不会提供太多有价值的信息.
- (2)ID3算法只能对描述属性为离散型属性的数据集构造决策树。
C4.5算法
做出的改进(为什么使用C4.5要好)
- (1)用信息增益率来选择属性
- (2)可以处理连续数值型属性
- (3)采用了一种后剪枝方法
- (4)对于缺失值的处理
C4.5算法的优缺点
- 优点:产生的分类规则易于理解,准确率较高。
- 缺点:在构造树的过程中,需要对数据集进行多次的顺序扫描和排序,因而导致算法的低效。
- 此外,C4.5只适合于能够驻留于内存的数据集,当训练集大得无法在内存容纳时程序无法运行。
CART算法 CART算法相比C4.5算法的分类方法,采用了简化的二叉树模型,同时特征选择采用了近似的基尼系数来简化计算。
C4.5不一定是二叉树,但CART一定是二叉树。
多变量决策树(multi-variate decision tree) 同时,无论是ID3, C4.5还是CART,在做特征选择的时候都是选择最优的一个特征来做分类决策,但是大多数,分类决策不应该是由某一个特征决定的,而是应该由一组特征决定的。这样决策得到的决策树更加准确。这个决策树叫做多变量决策树(multi-variate decision tree)。
在选择最优特征的时候,多变量决策树不是选择某一个最优特征,而是选择最优的一个特征线性组合来做决策。这个算法的代表是OC1,这里不多介绍。 如果样本发生一点点的改动,就会导致树结构的剧烈改变。这个可以通过集成学习里面的随机森林之类的方法解决。
什么情况下可以选择结束划分
3. cart剪枝
3.1. 为什么要剪枝
图形描述
- 横轴表示在决策树创建过程中树的结点总数,纵轴表示决策树的预测精度。
- 实线显示的是决策树在训练集上的精度,虚线显示的则是在一个独立的测试集上测量出来的精度。
- 随着树的增长,在训练样集上的精度是单调上升的, 然而在独立的测试样例上测出的精度先上升后下降。
后期产生了过拟合:
出现这种情况的原因:
- 原因1:噪声、样本冲突,即错误的样本数据。
- 原因2:特征即属性不能完全作为分类标准。
- 原因3:巧合的规律性,数据量不够大。
3.2. 常用的减枝方法
决策树可以做到对训练集 拟合,但过拟合的模型对测试样本而言没有价值,因此需要剪支来降低过拟合的风险。
剪枝,即通过主动去掉一些分支来降低过拟合的风险
预剪枝 从根节点开始,从上至下判断收起当前节点的分支后,验证集性能是否变好。若是,剪去当前节点,否则保留。
优点:降低过拟合;显著减少训练时间和测试时间开销
缺点:剪去的节点,虽然当前划分不能提升泛化性能,但在其基础上进行的后续划分却有可能导致性能显著提高。预剪枝基于"贪心"本质禁止这些分支展开给预剪枝决策树带来了欠拟含的风险。(通俗说就是后面无限的可能性被扼杀了)
后剪支 先从训练集生成一棵完整决策树,再从下往上剪支,剪支依据同上。
优点:欠拟合风险很小;泛化性能往往优于预剪枝
缺点:训练时间开销很大
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
- 随机数种子
决策树
保存树的结构到dot文件
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', 'pclass=3rd', '女性', '男性'])
#方法一:直接使用sklearn.tree自带的plot_tree()方法
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import plot_tree
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
iris = load_iris()
# 数据拆分
X = iris.data
y = iris.target
X_train,X_test,y_train,y_test = train_test_split(X, y, random_state=0, test_size=1/4)
# 训练模型
dt_model = DecisionTreeClassifier(max_depth=4)
dt_model.fit(X_train, y_train)
# 数据可视化
plt.figure(figsize=(15,9))
plot_tree(dt_model,filled=True,feature_names=iris.feature_names, class_names=iris.target_names)
plt.show()
#使用Graphviz
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import plot_tree
from sklearn.model_selection import train_test_split
from sklearn.tree import export_graphviz
import matplotlib.pyplot as plt
import graphviz
iris = load_iris()
# 数据拆分
X = iris.data
y = iris.target
X_train,X_test,y_train,y_test = train_test_split(X, y, random_state=0, test_size=1/4)
# 训练模型
dt_model = DecisionTreeClassifier(max_depth=4)
dt_model.fit(X_train, y_train)
# 数据可视化
tmp_dot_file = 'decision_tree_tmp.dot'
export_graphviz(dt_model, out_file=tmp_dot_file, feature_names=iris.feature_names, class_names=iris.target_names,filled=True, impurity=False)
with open(tmp_dot_file) as f:
dot_graph = f.read()
graphviz.Source(dot_graph)
案例实践:
案例:泰坦尼克号乘客生存预测
学习目标 通过案例进一步掌握决策树算法api的具体使用
泰坦尼克号沉没是历史上最臭名昭着的沉船之一。1912年4月15日,在她的处女航中,泰坦尼克号在与冰山相撞后沉没,在2000多名乘客和机组人员中造成1502人死亡。这场耸人听闻的悲剧震惊了国际社会,并为船舶制定了更好的安全规定。造成海难失事的原因之一是乘客和机组人员没有足够的救生艇。
尽管幸存者有一些运气因素,但有些人比其他人更容易生存,例如妇女,儿童和上流社会。在这个案例中,我们要求您完成对哪些人可能存活的分析。特别是,我们要求您运用机器学习工具来预测哪些乘客幸免于悲剧。
泰坦尼克号上有不同阶级、不同年龄的乘客两千多人,而在这次沉船事故中幸存下来的仅有718人。根据数据统计分析,人们发现,幸存的乘客和他们的年龄、性别、乘坐车舱等级等因素存在某种关系。
train_titantic.csv给出了当时泰坦尼克号上891位乘客的基本数据及其生存情况。本次实验在原始数据上进行数据处理,并通过决策树模型预测船上乘客的生存情况
获取的数据集: 字段名以及含义:
- PassengerId 乘客编号
- Survived 生存情况(1=存活,0=死亡)
- Pclass 船舱等级(1=头等舱,2=二等舱,3=三等舱)
- Name 姓名
- Sex 性别
- Age 年龄
- SibSp 兄弟姐妹数/配偶数(即同船的同代亲属人数)
- Parch 父母/子女数(即同船的不同代直系亲属人数)
- Ticket 船票编号
- Fare 船票价格
- Cabin 客舱号
- Embarked 登船港口(S=美国南安普顿,C=法国瑟堡市,Q=爱尔兰昆士敦)
2. 步骤分析
- 1.获取数据
- 2.数据基本处理
- 2.1 确定特征值,目标值
- 2.2 缺失值处理
- 2.3 数据集划分
- 3.特征工程
- 4.机器学习(决策树)
- 5.模型评估
3. 代码实现
#导入需要的模块
import pandas as pd
import numpy as np
from sklearn.feature_extraction import DictVectorizer
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, export_graphviz
# 1、获取数据
titan =pd.read_csv("/home/aistudio/data/data109235/train.csv")
titan.head(2)
titan.info()
#2.数据基本处理
#2.1 确定特征值,目标值
x = titan[["Pclass", "Age", "Sex"]]
y = titan["Survived"]
#2.2 缺失值处理
# 缺失值需要处理,将特征当中有类别的这些特征进行字典特征抽取
x['Age'].fillna(x['Age'].mean(), inplace=True)
#2.3 数据集划分
x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=22)
x_train.head()
x_train.shape
(668, 3)
字典特征提取DictVectorizer(特征工程之特征提取)_不懂六月飞雪的博客-CSDN博客_dictvectorizer 字典特征提取DictVectorizer(特征工程之特征提取)
#3.特征工程
###############################字典特征抽取######################################################
#特征中出现类别符号,需要进行one-hot编码处理(DictVectorizer)
#x.to_dict(orient="records") #需要将数组特征转换成字典数据
# 对于x转换成字典数据x.to_dict(orient="records")
#[{"pclass": "1st", "age": 29.00, "sex": "female"}, {}]
#
#transfer = DictVectorizer(sparse=False)
#x_train = transfer.fit_transform(x_train.to_dict(orient="records"))
#x_test = transfer.fit_transform(x_test.to_dict(orient="records"))
#print(x_train)
#############################one-hot编码处理################################################################
x_train.reset_index(drop=False,inplace=True) #重置索引 为合并做准备
x_test.reset_index(drop=False,inplace=True)
from sklearn.preprocessing import OneHotEncoder
ohe=OneHotEncoder()
fs=ohe.fit_transform(x_train[["Sex"]])
fs_one=pd.DataFrame(data=fs.toarray(),columns=["male","female"])
x_train=pd.concat([x_train,fs_one],axis=1)
x_train=x_train[["Pclass","Age","male","female"]]
#########################################################################################
fs=ohe.transform(x_test[["Sex"]])
fs_one=pd.DataFrame(data=fs.toarray(),columns=["male","female"])
x_test=pd.concat([x_test,fs_one],axis=1)
x_test=x_test[["Pclass","Age","male","female"]]
#########################################################################################
#4.决策树模型训练和模型评估
#决策树API当中,如果没有指定max_depth那么会根据信息熵的条件直到最终结束。这里我们可以指定树的深度来进行限制树的大小
# # 4.机器学习(决策树)
estimator = DecisionTreeClassifier(criterion="entropy", max_depth=5)
# # #estimator = DecisionTreeClassifier(criterion='gini', max_depth=5)
estimator.fit(x_train, y_train)
# # 5.模型评估
print(estimator.score(x_test, y_test))
estimator.predict(x_test)
x_test
y_train
# -*- coding: utf-8 -*-
#完整版
#导入panadas用于数据分析
import pandas as pd
#利用pandas的read_csv模块直接从互联网读入数据
titanic=pd.read_csv('/home/aistudio/data/data109235/train.csv')
#观察前几条数据,可以发现,数据种类各异,数值型、类别性,甚至还有缺失数据
#print(titanic.head())
#使用pandas,数据都传入独有的dataframe格式(二维数据表格),直接使用info(),查看数据的统计特性
#titanic.info()
#使用决策树模型预测泰坦尼克号乘客的生还情况
X=titanic[['Pclass','Age','Sex']]
y=titanic['Survived']
#对当前选择的特征进行探查
#X.info()
#补全age里面的数据,使用平均数或者中位数都是对模型偏离造成最小影响的策略
#第一个参数是填充的数据的平均数,第二个是替换设置为真
X['Age'].fillna(X['Age'].mean(),inplace=True)
#重新检查
#X.info()
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.25,random_state=33)
#导入特征转化器
from sklearn.feature_extraction import DictVectorizer
vec=DictVectorizer(sparse=False)
X_train=vec.fit_transform(X_train.to_dict(orient='records'))
print (vec.feature_names_)
print("*"*30)
print (X_train)
X_test=vec.transform(X_test.to_dict(orient='record'))
#导入决策树
from sklearn.tree import DecisionTreeClassifier
dtc=DecisionTreeClassifier(criterion="entropy", max_depth=5)
#使用分割到的训练数据进行模型学习
dtc.fit(X_train,y_train)
y_predict=dtc.predict(X_test)
#决策树模型对泰坦尼克号乘客是否生还的预测性能
from sklearn.metrics import classification_report
#输出预测的准确性
print(dtc.score(X_test,y_test))
#输出更加详细的分类性能
print(classification_report(y_test,y_predict,target_names=['Died','Survived']))
print(type(vec.feature_names_))
# 数据可视化
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
plt.figure(figsize=(20,10))
plot_tree(dtc,filled=True,feature_names=vec.feature_names_,class_names=['Died','Survived'])
plt.show()
#plot_tree?
['Age', 'Pclass', 'Sex=female', 'Sex=male'] ****************************** [[47. 1. 0. 1. ] [40. 3. 0. 1. ] [29.69911765 3. 0. 1. ] ... [25. 2. 0. 1. ] [21. 3. 0. 1. ] [35. 2. 0. 1. ]] 0.8251121076233184 precision recall f1-score support Died 0.84 0.87 0.86 134 Survived 0.80 0.75 0.77 89 accuracy 0.83 223 macro avg 0.82 0.81 0.82 223 weighted avg 0.82 0.83 0.82 223 <class 'list'>