C4.5就是使用这种方法处理缺少的属性值。
3.3 基尼指数
CART 决策树 [Breiman et al., 1984] 使用"基尼指数" (Gini index)来选择划分属性。
CART 是Classification and Regression Tree的简称,这是一种著名的决策树学习算法,分类和回归任务都可用
(1)概念
(2)案例
请根据下图列表,按照基尼指数的划分依据,做出决策树。
对数据集非序列标号属性{是否有房,婚姻状况,年收入}
分别计算它们的Gini指数,取Gini指数最小的属性作为决策树的根节点属性。
① 当根据是否有房来进行划分时,Gini指数计算过程为:
② 若按婚姻状况属性来划分,属性婚姻状况有三个可能的取值{married,single,divorced},(CART一定是二叉树)分别计算划分后的Gini指数:
对比计算结果,根据婚姻状况属性来划分根节点时取Gini指数最小的分组作为划分结果,即:{married} | {single,divorced}
③ 年收入Gini指数:
对于年收入属性为 数值型 属性,首先需要对数据按升序排序,然后从小到大依次用相邻值的中间值作为分隔将样本划分为两组。例如:当面对年收入为60和70这两个值时,我们算得其中间值为65。以中间值65作为分割点求出Gini指数
根据计算知道,三个属性划分根节点的指数最小的有两个:年收入和婚姻状况,他们的指数都为0.3。此时,选取首先出现的属性【婚姻状况】作为第一次划分。
接下来,采用同样的方法,分别计算剩下属性
① 对于是否有房属性,可得:
② 对于年收入属性则有:
选取属性【是否有房】作为第二次划分
经过如上流程,构建的决策树,如下图:
3.4 小结
(1) ID3 决策树算法的缺点
- ID3算法在选择根节点和各内部节点中的分支属性时,采用信息增益作为评价标准。信息增益的缺点是倾向于选择取值较多的属性,在有些情况下这类属性可能不会提供太多有价值的信息.
- ID3算法只能对描述属性为离散型属性的数据集构造决策树
(2) C4.5 决策树算法
-
做出的改进(为什么使用C4.5要好)
- 用信息增益率来选择属性
- 除了可以处理离散型描述属性,还可以处理连续数值型属性
- 采用了一种后剪枝方法
- 对于缺失值的处理
-
优点:
- 产生的分类规则易于理解,准确率较高。
-
缺点:
- 在构造树的过程中,需要对数据集进行多次的顺序扫描和排序,因而导致算法的低效。
- 此外,C4.5只适合于能够驻留于内存的数据集,当训练集大得无法在内存容纳时程序无法运行。
(3)CART 决策树算法
- CART算法相比C4.5算法的分类方法,采用了简化的二叉树模型,同时特征选择采用了近似的基尼系数来简化计算。
- C4.5不一定是二叉树,但CART一定是二叉树。
4. cart 剪枝
4.1 为何要 cart 剪枝
图形描述:
- 横轴表示在决策树创建过程中树的结点总数,纵轴表示决策树的预测精度。
- 实线显示的是决策树在训练集上的精度,虚线显示的则是在一个独立的测试集上测量出来的精度。
- 随着树的增长,在训练样集上的精度是单调上升的, 然而在独立的测试样例上测出的精度先上升后下降。
出现这种情况的原因:
- 噪声、样本冲突,即错误的样本数据。
- 特征即属性不能完全作为分类标准。
- 巧合的规律性,数据量不够大。
剪枝 (pruning)是决策树学习算法对付"过拟合"的主要手段。
在决策树学习中,为了尽可能正确分类训练样本,结点划分过程将不断重复,有时会造成决策树分支过多,这时就可能因训练样本学得"太好"了,以致于把训练集自身的一些特点当作所有数据都具有的一般性质而导致过拟合。因此,可通过主动去掉一些分支来降低过拟合的风险。
4.2 常用的剪枝方法
决策树剪枝的基本策略有"预剪枝" (pre-pruning)和"后剪枝"(post- pruning) 。
(1)预剪枝
预剪枝是指在决策树生成过程中,对每个结点在划分前先进行估计,若当前结点的划分不能带来决策树泛化性能提升,则停止划分并将当前结点标记为叶结点;
(2)后剪枝
后剪枝则是先从训练集生成一棵完整的决策树,然后自底向上地对非叶结点进行考察,若将该结点对应的子树替换为叶结点能带来决策树泛化性能提升,则将该子树替换为叶结点。
对比两种剪枝方法:
- 后剪枝决策树通常比预剪枝决策树保留了更多的分支。
- 一般情形下,后剪枝决策树的欠拟合风险很小,泛化性能往往优于预剪枝决策树。
- 但后剪枝过程是在生成完全决策树之后进行的。 并且要自底向上地对树中的所有非叶结点进行逐一考察,因此其训练时间开销比未剪枝决策树和预剪枝决策树都要大得多。
5. 特征工程—特征提取
将任意数据(如文本或图像)转换为可用于机器学习的数字特征(特征值化是为了计算机更好的去理解数据)
除此之外,我们还可以在数据预处理过程中将离散的特征数据进行OneHot独热编码。
from sklearn.preprocessing import OneHotEncoder
enc = OneHotEncoder()
enc.fit([[0,0,3],[1,1,0],[0,2,1],[1,0,2]]) # 训练。这里共有4个数据,3种特征
array = enc.transform([[0,1,3]]).toarray() # 测试。这里使用1个新数据来测试
print(array) # [[ 1 0 0 1 0 0 0 0 1]] # 独热编码结果
特征提取分类:
- 字典特征提取(特征离散化)
- 文本特征提取
- 图像特征提取(深度学习将介绍)
特征提取API:sklearn.feature_extraction
5.1 字典特征提取
作用:对字典数据进行特征值化
sklearn.feature_extraction.DictVectorizer(sparse=True,…)
- DictVectorizer.fit_transform(X)
- X:字典或者包含字典的迭代器返回值
- 返回sparse矩阵
- DictVectorizer.get_feature_names() 返回类别名称
案例:
我们对以下特征进行提取
[{'city': '北京','temperature':100},
{'city': '上海','temperature':60},
{'city': '深圳','temperature':30}]
from sklearn.feature_extraction import DictVectorizer
data = [{'city': '北京', 'temperature': 100},
{'city': '上海', 'temperature': 60},
{'city': '深圳', 'temperature': 30}]
# 1. 实例化一个转换器类
transfer = DictVectorizer() # 默认sparse=True
# 2. 调用fit\_transform方法输入数据并转换(注意返回格式)
data = transfer.fit_transform(data)
print("返回的结果:\n", data)
# 打印每一列特征名字
names = transfer.get_feature_names()
print(names)
若为transfer = DictVectorizer(sparse=False)
的结果(非sparse矩阵)
sparse=True
的作用
- 提高读取效率
- 节省内存空间
注意:对于特征当中存在类别信息的我们都会做 one-hot 编码处理
5.2 文本特征提取
作用:对文本数据进行特征值化
sklearn.feature_extraction.text.CountVectorizer(stop_words=[])
- 返回词频矩阵
- 参数
stop_words
:停用词 CountVectorizer.fit_transform(X)
- X:文本或者包含文本字符串的可迭代对象
- 返回值:返回sparse矩阵
CountVectorizer.get_feature_names()
返回值:单词列表
sklearn.feature_extraction.text.TfidfVectorizer
(1)英文文本特征提取
我们对以下数据进行特征提取
["life is short,i like python",
"life is too long,i dislike python"]
from sklearn.feature_extraction.text import CountVectorizer
data = ["life is short,i like like python", "life is too long,i dislike python"]
# 1. 实例化类CountVectorizer
transfer = CountVectorizer() # 要注意CountVectorizer()没有sparse这个参数
# 2. 调用fit\_transform方法输入数据并转换
# (注意返回格式,利用toarray()将sparse矩阵转换array数组)
data = transfer.fit_transform(data)
print(data)
print(data.toarray())
print("特征名称为:\n",transfer.get_feature_names())
注意:
- 单个字符的单词以及标点符号不做统计
- 英文默认是以空格分开的,其实就达到了一个分词的效果
(2)中文文本特征提取
我们要对中文进行分词处理,需要利用 jieba 分词处理
jieba库的简单用法见:https://blog.csdn.net/hu_wei123/article/details/127121301
对以下三句话进行特征值化
今天很残酷,明天更残酷,后天很美好,
但绝对大部分是死在明天晚上,所以每个人不要放弃今天。
我们看到的从很远星系来的光是在几百万年之前发出的,
这样当我们看到宇宙时,我们是在看它的过去。
如果只用一种方式了解某样事物,你就不会真正了解它。
了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。
from sklearn.feature_extraction.text import CountVectorizer
import jieba
data = ["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
"我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
"如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]
text_list = []
for sentence in data:
text = " ".join(jieba.lcut(sentence))
# print(text)
text_list.append(text)
print(text_list)
# 1. 实例化一个转化器类
transfer = CountVectorizer()
# 2. 调用fit\_transform
data = transfer.fit_transform(text_list)
print("文本特征抽取的结果:\n", data.toarray())
print("返回特征名字:\n", transfer.get_feature_names())
文本特征抽取的结果:
[[2 0 1 0 0 0 2 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 2 0 1 0 2 1 0 0 0 1 1 0 0 1 0]
[0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 1 3 0 0 0 0 1 0 0 0 0 2 0 0 0 0 0 1 0 1]
[1 1 0 0 4 3 0 0 0 0 1 1 0 1 0 1 1 0 1 0 0 1 0 0 0 1 0 0 0 2 1 0 0 1 0 0 0]]
返回特征名字:
['一种', '不会', '不要', '之前', '了解', '事物', '今天', '光是在', '几百万年', '发出', '取决于', '只用', '后天', '含义', '大部分', '如何', '如果', '宇宙', '我们', '所以', '放弃', '方式', '明天', '星系', '晚上', '某样', '残酷', '每个', '看到', '真正', '秘密', '绝对', '美好', '联系', '过去', '还是', '这样']
(3)Tf-idf文本特征提取
TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
TF-IDF的作用:用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度
TF-IDF的重要性:分类机器学习算法进行 文章分类 中前期数据处理方式
- 词频(term frequency,tf):指的是某一个给定的词语在该文件中出现的频率
- 逆向文档频率(inverse document frequency,idf):是一个词语普遍重要性的度量。某一特定词语的idf,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取以10为底的对数得到
最终得出结果 tfidf 可以理解为重要程度
举例:
假如一篇文章的总词语数是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
其 api 用法同上述中文特征提取
6. 决策树的使用
6.1 决策树 api 介绍
sklearn.tree.DecisionTreeClassifier(criterion=’gini’,max_depth=None,random_state=None)
参数:
-
criterion
:特征选择标准- 值为"gini"或者"entropy",前者代表基尼系数,后者代表信息增益。一默认"gini",即CART算法。
-
max_depth
:决策树最大深度- 默认可以不输入,如果不输入的话,决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间
-
random_state
:随机数种子 -
min_samples_split
:内部节点再划分所需最小样本数- 这个值限制了子树继续划分的条件,如果某节点的样本数少于min_samples_split,则不会继续再尝试选择最优特征来进行划分。 默认是2.如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。我之前的一个项目例子,有大概10万样本,建立决策树时,我选择了min_samples_split=10。可以作为参考。
-
min_samples_leaf
:叶子节点最少样本数- 这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝。 默认是1,可以输入最少的样本数的整数,或者最少样本数占样本总数的百分比。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。之前的10万样本项目使用min_samples_leaf的值为5,仅供参考。
sklearn.tree.export_graphviz()
- 该函数能够导出DOT格式
tree.export_graphviz(estimator,out_file='tree.dot’,feature_names=[‘’,’’])
6.2 案例:泰坦尼克号乘客生存预测
泰坦尼克号沉没是历史上最臭名昭着的沉船之一。1912年4月15日,在她的处女航中,泰坦尼克号在与冰山相撞后沉没,在2224名乘客和机组人员中造成1502人死亡。这场耸人听闻的悲剧震惊了国际社会,并为船舶制定了更好的安全规定。 造成海难失事的原因之一是乘客和机组人员没有足够的救生艇。尽管幸存下沉有一些运气因素,但有些人比其他人更容易生存,例如 妇女,儿童和上流社会 (也就是与性别 Sex、年龄 Age、社会阶层 Pclass有关)。 在这个案例中,我们要求您完成对哪些人可能存活的分析。特别是,我们要求您运用机器学习工具来预测哪些乘客幸免于悲剧。
经过观察数据得到,其中 Age 数据存在缺失。
泰坦尼克号数据集获取:https://pan.baidu.com/s/13L6UxNxd2XzgA0rERsXHrg?pwd=blhx
本数据集是从kaggle平台获取,为了实验方便并将train.csv
重命名为titanic.csv
,读者也可直接从kaggle平台:https://www.kaggle.com/c/titanic/overview,自行下载实验
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.获取数据
titanic = pd.read_csv("./titanic.csv")
# 2.数据基本处理
# 2.1 确定特征值,目标值
x = titanic[["Sex","Age","Pclass"]]
y = titanic["Survived"]
# 2.2 缺失值处理
# nan\_num = titanic["Age"].isnull().sum()
# print(num) # Age列有177个空缺值
# 用Age列的平均值填充空缺值
x['Age'].fillna(x['Age'].mean(), inplace=True)
# 2.3 数据集划分
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=1)# 默认测试集0.25的划分比例
# 3.特征工程(字典特征抽取)
# 对于x转换成字典数据,转换后list形式
# [{"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"))
# 4.机器学习(决策树)
estimator = DecisionTreeClassifier(max_depth=5)
estimator.fit(x_train,y_train)
# 5.模型评估
y_pre = estimator.predict(x_test)
score = estimator.score(x_test,y_test)
# 6.决策树可视化
export_graphviz(estimator, out_file="./tree.dot", feature_names=['Age', 'Pclass','male', 'female'])
pandas关于to_dict的使用:https://blog.csdn.net/qq_38060702/article/details/109843385
7. 回归决策树
前面已经讲到,关于数据类型,我们主要可以把其分为两类,连续型数据和离散型数据。在面对不同数据时,决策树也可以分为两大类型:
- 分类决策树主要用于处理离散型数据
- 回归决策树主要用于处理连续型数据。
7.1 原理概述
不管是回归决策树还是分类决策树,都会存在两个核心问题:
- 如何选择划分点?
- 如何决定叶节点的输出值?
7.2 算法描述
输入:训练数据集 D
输出:回归树 f(x)
流程:在训练数据集所在的输入空间中,递归的将每个区域划分为两个子区域并决定每个子区域上的输出值
7.3 简单实例
为了易于理解,接下来通过一个简单实例加深对回归决策树的理解。
训练数据见下表,目标是得到一棵最小二乘回归树。
(1)选择最优的切分特征 j 与最优切分点 s
a. 计算子区域输出值:
b. 计算损失函数值,找到最优切分点:
(2)用选定的(j,s)划分区域,并决定输出值
(3)调用步骤 (1)、(2),继续划分
(4)生成回归树
7.4 回归决策树和线性回归对比
![img](https://img-blog.csdnimg.cn/img_convert/2fbfe24f759f31f13221ac2e09743081.png)
![img](https://img-blog.csdnimg.cn/img_convert/6933c1d29318ecf61bd22ea6cad966f6.png)
![img](https://img-blog.csdnimg.cn/img_convert/065ab626bd7092a97f8e69137538984b.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**
/img-blog.csdnimg.cn/a604b68709f7430a8552a25f0ce31b48.png)
**(3)调用步骤 (1)、(2),继续划分**
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/cc154e72e8867507dfb40514aba96b46.png)
**(4)生成回归树**
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/2c7429fda5f3b9e50ef6d3bb8001ae67.png)
### 7.4 回归决策树和线性回归对比
[外链图片转存中…(img-SKMZIsnq-1714201896114)]
[外链图片转存中…(img-wbu5dpM0-1714201896115)]
[外链图片转存中…(img-kOWW02Eg-1714201896115)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新