python机器学习 | 决策树算法介绍及实现
最近天气变得特别冷,之前每每遇到周末,我都想出去玩,现在冻到只想躲在温室里过冬,真的too too cold ~
周六看了一本书《你像鸟飞往你的山》,本来是想通过看书平静一下自己浮躁的心绪,结果看得有些些压抑,这算是平静过头了吗。。。哈哈,这篇博文主要讲的是决策树算法的内容
学习了如下博客:
1.决策树算法及Python实现
2.决策树算法介绍
决策树算法介绍及实现
1 决策树算法介绍
1.1 决策树算法的引入
决策一词,我们并不陌生。在日常生活中我们会遇到各种各样的决策,做决策过程中,我们要(逐步)考虑各种因素的重要性,然后做出A选择,或者B选择。进一步分析,A、B选择就是一个分类的问题,而决策树算法在这里就应用了。
决策树(Decision Tree)是一种基本的分类与回归方法,它是基于特征对数据进行分类并由此构造树的过程。
那么构造就是生成一颗完整的决策树。构造的过程就是选择什么属性作为节点的过程,那么在构造过程中,会存在三种节点:
- 根节点:决策中最具有决定性的,
- 内部节点:决策中考虑到的所有特征
- 叶节点:决策的结果
下面通过一个例子简单介绍这几个节点以及决策树如何构造,假设母上大人想要介绍一个人给您认识,这个时候,你要考虑要不要出去见他(这里就是决策啦):
上图完整表达了一个决策的策略。首先,红框中的性别既是根节点也是内部节点(这是争对一整棵大树而言的根节点),它是分类最清楚的;其次,蓝框中的是内部结点,表示判断条件,也就是决策考虑的因素特征,绿框表示叶结点,表示决策结果,箭头表示在一个判断条件在不同情况下的决策路径。
所以在构造树的过程中,我们需要解决三个重要的问题:
- 选择哪个属性作为根节点
- 选择哪些属性作为子节点
- 什么时候停止并且得到目标状态
换言之,我们的目标是通过一种衡量标准,来计算通过不同特征进行分支选择后的分类情况,评判分支选择的好坏,找出来最好的那个当成根节点,以此类推。
1.2 决策树算法步骤
决策树构建的基本步骤如下:
- 开始,所有记录看作一个节点(如上例的性别、年龄、长相、收入等)
- 遍历每个特征的每一种分裂方式,找到最好的分裂特征,分类最纯(根节点,例子是性别,如果是男的,直接不见)
- 分裂成两个或多个节点(如果是女的,那么还要再考虑其他因素,再决定见还是不见)
- 对分裂后的节点分别继续执行2-3步,直到每个节点足够“纯”为止
如何评估分裂点的好坏?如果一个分裂点可以将当前的所有节点分为两类,使得每一类都很“纯”,也就是同一类的记录较多,那么就是一个好分裂点(根节点)。
具体实践中,到底选择哪个特征作为当前分裂特征(当前分类树的根节点),常用的有下面三种算法:
- ID3:使用信息增益g(D,A)进行特征选择
- C4.5:信息增益率 =g(D,A)/H(A)
- CART:基尼系数
总结:一个特征的信息增益(或信息增益率,或基尼系数)越大,表明特征对样本的熵的减少能力更强,这个特征使得数据由不确定性到确定性的能力越强。
2 决策树算法分类
2.1 信息熵(Entropy)
- 介绍:在介绍算法前,先介绍数据不确定性的度量,信息熵。其实熵这个词我们在高中化学课本就学到了,当熵越大,数据的“整齐”程度就越低,当越小,数据的“整齐”程度就越高。间而言之,信息熵是表示随机变量不确定性的度量。
- 公式:p表示概率
总结:概率越大,混乱程度越低,熵值越低,数据越纯,分类越明显。比如说:
2.2 ID3算法(信息增益)
2.2.1 介绍
- 介绍:熵可以表示样本集合的不确定性,熵越大,样本的不确定性就越大。因此可以使用划分前后集合熵的差值来衡量使用当前特征对于样本集合Y划分效果的好坏。信息增益表示特征X使得类Y的不确定性减少的程度。
2.2.2 公式
- 公式:特征A对训练数据集D的信息增益g(D,A),定义为集合D的信息熵H(D)与特征A给定条件下D的信息条件熵H(D|A)之差,即公式为:
具体为:
- 信息熵计算
- 条件熵计算
2.2.3 举例
- 举例
如下图,我们根据天气,温度,湿度,刮风,四个特征来判断是否打球。
"""
得出信息:
• 数据集:7天打球情况
• 特征:4种环境变化(天气,温度,湿度,刮风)
• 目标:构造决策树
梳理计算流程:
• 计算初始熵
• 计算各特征的熵
• 进行求差得信息增益
• 选择信息增益最大的
"""
"""
1.计算初始熵
• 样本数据共:7
• 不打球:4
• 打球:3
"""
# -(不打球的概率 * 不打球概率的对数 + 打球的概率 * 打球概率的对数)
s_ent = -((4/7) * np.log2(4/7) + (3/7) * np.log2(3/7))
print(s_ent)
"""
计算各特征的熵
以天气特征为例
• 晴天的熵:共3条,2条不打球,1条打球
• 阴天的熵:共2条,1条不打球,1条打球
• 小雨的熵:共2条,1条不打球,1条打球
因为天气特征的三个子特征每个出现的概率都不一样,所以需要进行加权。
• 晴天出现的概率:3/7
• 阴天出现的概率:2/7
• 小雨出现的概率:2/7
"""
ent_sunny = -((2/3)*np.log2(2/3) + (1/3)*np.log2(1/3))
ent_overcast = -((1/2)*np.log2(1/2) + (1/2)*np.log2(1/2))
ent_rainy = -((1/2)*np.log2(1/2) + (1/2)*np.log2(1/2))
# print(ent_sunny,ent_overcast,ent_rainy)
ent_outlook = (3/7)*ent_sunny + (2/7)*ent_overcast + (2/7)*ent_rainy
print(ent_outlook)
"""
其他三个特征同理上述,最后得到的各个特征的熵值为如下。
"""
ent_outlook = 0.9649839288804954
ent_temp = 0.865198660327952
ent_humidity = 0.9649839288804954
ent_windy = 0.9649839288804954
"""
求信息增益
"""
print(f"天气的信息增益:{s_ent - ent_outlook}\n温度的信息增益:{s_ent - ent_temp}\n湿度的信息增益:{s_ent - ent_humidity}\n刮风的信息增益:{s_ent - ent_windy}")
基于上述结果,我们知道温度的信息增益最大,也就是该节点划分的数据越纯。那么需要再从湿度、天气等中去选择子节点,同上可构建完整的决策树。
如基于温度的分配结果是:(1)低温 不打篮球,不需要再选择节点;(2)中温 打(1个),不打(1)个;(3)高温 打(3个),不打(1)个;那么,我们就需要对中温和高温以节点再一次进行如上流程:
- 分别计算中温和高温的初始熵
- 计算湿度、天气、刮风的熵
- 进行求差得信息增益
- 选择信息增益越大的
2.2.4 评价
- ID3没有考虑连续特征,比如长度,密度都是连续值,无法在ID3运用。这大大限制了ID3的用途;
- ID3采用信息增益大的特征优先建立决策树的节点。缺点是在相同条件下,取值比较多的特征比取值少的特征信息增益大。如对于ID.,每条数据都对应一个play值,即按此特征划分,每个划分都是纯的(即完全的划分,只有属于一个类别),ID的信息增益为最大值1.但这种按该特征的每个值进行分类的方式是没有任何意义的。所以为了克服这一弊端,有人提出了采用信息增益率(GainRate)来选择分裂特征(根节点)。
- ID3算法对于缺失值的情况没有做考虑;
- 没有考虑过拟合的问题。
2.3 C4.5算法(信息增益率)
2.3.1 介绍
- 介绍:ID3 在计算的时候,倾向于选择取值多的属性。为了避免这个问题,C4.5 采用信息增益率的方式来选择属性。
2.3.2 公式
信息增益率 = 信息增益 / 属性熵
2.3.2 举例
"""
承接上面的例子
ent_outlook = 0.9649839288804954 ## 天气的熵
ent_temp = 0.865198660327952 ## 温度的熵
ent_humidity = 0.9649839288804954 ## 湿度的熵
ent_windy = 0.9649839288804954 ##刮风的熵
天气的信息增益:0.020244207153756077
温度的信息增益:0.12002947570629952
湿度的信息增益:0.018244207153756076
刮风的信息增益:0.019244207153756077
"""
# 计算特征的信息增益率 信息增益率 = 信息增益 / 属性熵
outlook_in = 0.020244207153756077/0.9649839288804954
temp_in = 0.12002947570629952/0.865198660327952
humidity_in = 0.018244207153756076/0.9649839288804954
wind_in = 0.019244207153756077/0.9649839288804954
print(f"天气的信息增益率:{outlook_in}\n温度的信息增益率:{temp_in}\n湿度的信息增益率:{humidity_in}\n刮风的信息增益率:{wind_in}")
同理,基于上述结果,我们知道温度的信息增益最大。
2.3.4 评价
- C4.5生成的是多叉树(ID3算法生成的也是多叉树),即一个父节点可以有多个子节点。很多时候,在计算机中二叉树模型会比多叉树运算效率高。如果采用二叉树,可以提高效率;
- C4.5只能用于分类,不能应用于回归,这也大大的限制了它的用途;
- C4.5由于使用了熵模型,里面有大量的耗时的对数运算,如果是连续值还有大量的排序运算。如果能够加以模型简化可以减少运算强度但又不牺牲太多准确性的话,那就更好了。
基于上面的4个问题,在CART树中进行了部分的改进
2.4 CART算法(基尼系数)
2.4.1 介绍
- 介绍:CART 算法,英文全称叫做 Classification And Regression Tree,中文叫做分类回归树。ID3 和 C4.5 算法可以生成二叉树或多叉树,而 CART 只支持二叉树。同时 CART 决策树比较特殊,既可以作分类树,又可以作回归树。它是在给定输入随机变量X条件下输出随机变量Y的条件概率分布的学习方法。CART在构建决策树用的是二叉树结构,所以在每个叶节点上预测的是概率分布,也就是在输入给定的条件下输出的条件概率分布。
2.4.2 公式
- 计算流程:1)CART分类树与C4.5算法类似,只是在属性选择的衡量指标(熵值)采用的是基尼系数。基尼系数本身反应了样本的不确定度。当基尼系数越小的时候,说明样本之间的差异性小,不确定程度低。2)对回归树用平方误差最小化准则(mse)或绝对误差最小化准则(mae)
- 公式:
1)分类树公式中的基尼系数
2)回归树中的均方误差
2.4.3 分类树举例
一般我们很少用决策树进行回归,所以举例分类树
2.4.3.1 离散型
"""
基尼系数构建决策树
• 计算初始基尼系数
• 分别计算各特征的基尼系数
• 做差计算基尼系数增益
"""
"""
计算最初始的基尼系数
- 7
- 不打球:4
- 打球:3
"""
s_gini = 1 - ((4/7)**2 + (3/7)**2)
print(s_gini)
"""
计算 各特征的基尼系数
计算 天气特征 的基尼系数
- 晴天的基尼系数:共3条,2条不打球,1条打球
- 阴天的基尼系数:共2条,1条不打球,1条打球
- 小雨的基尼系数:共2条,1条不打球,1条打球
"""
gini_sunny = 1 - (2/3)**2 - (1/3)**2
gini_overcast = 1 - (1/2)**2 - (1/2)**2
gini_rainny = 1 - (1/2)**2 - (1/2)**2
print(gini_sunny,gini_overcast,gini_rainny)
"""
计算天气特征的基尼系数,需加权
- 晴天出现的概率:3/7
- 阴天出现的概率:2/7
- 小雨出现的概率:2/7
"""
gini_out = (3/7)*gini_1 + (2/7)*gini_2 + (2/7)*gini_3
print(gini_out)
"""
基尼系数增益
做差计算基尼系数增益
"""
s_gini - gini_out
2.4.3.2 连续型
在实际过程中,我们有很多连续值,比如下图年收益,其实就是数值型的属性,而Cart算法又是二叉树,那么如何计算其基尼系数呢?
方法如下:
- 将乱序的值进行从小到大排序
- 不断的二分
如下图以65作为分割点,连续型数据的处理过程是将连续值进行离散化的过程。
"""
定义初始的基尼系数
"""
s_gini_2 = 1 - (3/10)**2 - (7/10)**2
print(s_gini_2)
"""
<=65这边的基尼系数
- 只有60小于65的,所以个数为1。但是并没有拖欠贷款,它的值为0
"""
gini_left = 1 - 1
print(gini_left)
"""
>65这边的基尼系数
- >65的有9个
- 6个无贷款
- 3个有贷款
"""
gini_right = 1 - (6/9)**2 - (3/9)**2
print(gini_right)
"""
计算整个的基尼系数,乘以权重累和
"""
num_gini = (1/10)*gini_left + (9/10)*gini_right
print(num_gini)
"""
计算基尼增益
"""
print(s_gini_2 - num_gini)
2.5 算法间的比较
学习自:决策树算法介绍
3 决策树的其他讨论
3.1 剪枝
- 介绍:剪枝就是给决策树瘦身,这一步想实现的目标就是,不需要太多的判断,同样可以得到不错的结果。之所以这么做,是为了防止“过拟合”(Overfitting)现象的发生。
- 分类:预剪枝和后剪枝
- 预剪枝
- 指定树的高度或者深度
- 每一个结点所包含的最小样本数目
- 指定结点的熵小于某个值,不再划分。
- 后剪枝
-
在已生成过拟合决策树上进行剪枝,可以得到简化版的剪枝决策树。
-
CART剪枝步骤
- 从原始决策树生成各种剪枝效果的决策树;
- 用交叉验证来检验剪枝后的预测能力,选择泛化预测能力最好的剪枝后的树作为最终的CART树。
3.2 特征提取
- 介绍:特征提取就是将任意数据转换为可用于机器学习的数字特征。主要分为:1)字典特征提取(特征离散化);2)文本特征提取
3.2.1 字典特征提取
-
作用:对类别数据进行转换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kmw99ETy-1606030348833)(attachment:image.png)] -
API介绍:
sklearn.feature_extraction.DictVectorizer(sparse=True,…)
-
DictVectorizer.fit_transform(X)。其中 : 1)X:字典或者包含字典的迭代器返回值;2)返回sparse矩阵
-
DictVectorizer.get_feature_names() 返回类别名称
"""
字典特征提取(one-hot编码,热编码)
默认返回sparse矩阵
- 可以指定sparse=False来不返回sparse矩阵
- 如果数据量小,可以不使用sparse矩阵:指定参数为False。这样更加方便我们自己查看
- 如果数据量大,sparse矩阵少了很多0,进而节省内存,效率会高一点。
"""
# 导入模块
from sklearn.feature_extraction import DictVectorizer
# 构建数据
data = [{'city': '长沙','temperature':20},
{'city': '深圳','temperature':25},
{'city': '广州','temperature':23}]
# 实例化
transfer = DictVectorizer(sparse=True) # 返回sparse矩阵
# 调用 fit_transform
trans_data = transfer.fit_transform(data)
print("特征名称是:\n",transfer.get_feature_names())
print(trans_data) # sparse矩阵,举例(0,2),0:data里面的索引 广州 2:表示特征名称里面出现的索引
# 导入模块
from sklearn.feature_extraction import DictVectorizer
# 构建数据
data = [{'city': '长沙','temperature':20},
{'city': '深圳','temperature':25},
{'city': '广州','temperature':23}]
# 实例化
transfer = DictVectorizer(sparse=False) # 不返回sparse矩阵
# 调用 fit_transform
trans_data = transfer.fit_transform(data)
print("特征名称是:\n",transfer.get_feature_names())
print(trans_data)
3.2.2 文本特征提取
- 作用:对文本数据进行特征值化
- API
sklearn.feature_extraction.text.CountVectorizer(stop_words=[])
- 返回词频矩阵
- CountVectorizer.fit_transform(X)
- X:文本或者包含文本字符串的可迭代对象
- 返回值:返回sparse矩阵
- CountVectorizer.get_feature_names() 返回值:单词列表
3.2.2.1 英文文本特征
"""
英文文本特征提取实现
需求:体现以下段落的词汇出现的频次
- 在特征提取,单个的字母不做统计
- 文本特征提取没有sparse参数
"""
# 导入模块
from sklearn.feature_extraction.text import CountVectorizer
# 设定数据
data = ["Life is a never - ending road", "I walk, walk, keep walking."]
# 实例化
trans = CountVectorizer()
# trans = CountVectorizer(sparse=False) # 报错:文本特征提取没有sparse参数
# 调用fit_transform
trans_data = trans.fit_transform(data)
print(trans.get_feature_names())
print(trans_data) # sparse矩阵,举例(0,3),0:data里面的索引 3:表示特征名称里面出现的索引
print(trans_data.toarray()) # 使用toarray将数据转为非sparse矩阵 非sparse矩阵:(0,0) 0行:在data中,索引为0的这一行 0列:在特征名称索引为0的这个元素
3.2.2.2 中文文本特征
- 运用 jieba 模块 来对中文文本进行断词
- CountVectorizer.get_feature_names() 返回值:单词列表
"""
txt文件里面的文本进行特征提取
- 读取txt文件 格式需:["第一行","第二行","第n行"]
- 取出data列表里面的每一行,进行分词,构建分词后的数据列表
"""
import jieba # pip install jieba
def cut_word(sent):
# jieba.cut("这一次相遇") # 进行分词,返回生成器对象
# list(jieba.cut("这一次相遇")) # ['这', '一次', '相遇'] --> ["这 一次 相遇"]
return " ".join(list(jieba.cut(sent)))
with open("论文.txt","r") as f:
# print(f.readlines())
data = [line.replace("\n","") for line in f.readlines()]
print(data)
lis = []
for line in data:
# print(cut_word(line))
lis.append(cut_word(line))
print(lis)
# 实例化
trans_c = CountVectorizer()
# 调用fit_transform
trans_data_c = trans_c.fit_transform(lis)
print(trans_c.get_feature_names())
print(trans_data_c)
print(trans_data_c.toarray())
3.2.2.2 Tf-idf文本特征提取
- 介绍:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
- 作用:用于评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。
- 公式
- 词频(term frequency,tf)指的是某一个给定的词语在该文件中出现的频率
- 逆向文档频率(inverse document frequency,idf)是一个词语普遍重要性的度量。某一特定词语的idf,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取以10为底的对数得到
- API:sklearn.feature_extraction.text.TfidfVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
with open("论文.txt","r") as f:
# print(f.readlines())
data = [line.replace("\n","") for line in f.readlines()]
# print(data)
lis = []
for line in data:
# print(cut_word(line))
lis.append(cut_word(line))
# 实例化
trans_c = TfidfVectorizer()
# 调用fit_transform
trans_data_c = trans_c.fit_transform(lis)
print(trans_c.get_feature_names())
print(trans_data_c)
print(trans_data_c.toarray())
4 决策树算法API
4.1 分类API
4.1.1 介绍
- 模块:
from sklearn.tree import DecisionTreeClassifier
- 实例化
clf = DecisionTreeClassifier(criterion=entropy)
- entropy: 基于信息熵,也就是 ID3 算法,实际结果与 C4.5 相差不大;
- gini:默认参数,基于基尼系数。CART 算法是基于基尼系数做属性划分的,所以 criterion=gini 时,实际上执行的是 CART 算法。
DecisionTreeClassifier(
*,
criterion='gini',
splitter='best',
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.0,
max_features=None,
random_state=None,
max_leaf_nodes=None,
min_impurity_decrease=0.0,
min_impurity_split=None,
class_weight=None,
presort='deprecated',
ccp_alpha=0.0,
)
• splitter:在构造树时,选择属性特征的原则,可以是best或者random。默认是best,best代表在所有的特征中选择最好的,random代表在部分特征中选择最好的。
• max_depth:决策树的最大深度,我们可以控制决策树的深度来防止决策树过拟合。
• min_samples_split:当节点的样本数少于min_samples_split时,不再继续分裂。默认值为2.
• min_samples_leaf:叶子节点需要的最少样本数。如果某叶子节点数目小于这个阈值,则会和兄弟节点一起被剪枝。可为int类型,也可为float类型。
• max_leaf_nodes:最大叶子节点数。int类型,默认情况下无需设置,特征不多时,不用设置。特征多时,可以通过该属性来防止过拟合。
4.1.2 示例
- 泰坦尼克号乘客生存预测示例
1. 需求:读取以下数据,预测生存率。
2. train.csv 是训练数据集,包含特征信息和存活与否的标签;
3. test.csv: 测试数据集,只包含特征信息
# 导入模块
from sklearn.tree import DecisionTreeClassifier
import numpy as np
import pandas as pd
# 数据描述
train_data = pd.read_csv("train.csv")
test_data = pd.read_csv("test.csv")
"""
目标:Survived
特征:
- Age 有缺失值
- Carbin 大量缺失值
- Embarked 有缺失值
"""
print(train_data.info())
print(train_data.head())
"""
无目标值
- Age 有缺失值
- Carbin 大量缺失值
- Fare 有缺失值
"""
print(test_data.info())
print(test_data.head())
# 数据处理
"""
Age
Fare
进行处理
"""
# 处理 年龄 替换 --> 使用平均年龄来进行填充nan
train_data["Age"] = train_data["Age"].fillna(train_data["Age"].mean())
test_data["Age"] = test_data["Age"].fillna(test_data["Age"].mean())
# 使用平均票价来进行填充nan
train_data["Fare"] = train_data["Fare"].fillna(train_data["Fare"].mean())
test_data["Fare"] = test_data["Fare"].fillna(test_data["Fare"].mean())
"""
Carbin:缺失量太大,不做处理
Embarked:3个港口,S、C、Q,以出现做多的来进行填充,所以填充为"S"
"""
train_data["Embarked"].value_counts()
train_data["Embarked"] = train_data["Embarked"].fillna("S")
test_data["Embarked"] = test_data["Embarked"].fillna("S")
# 特征选择
## 特征选择构建
features = ["Pclass","Sex","Age","SibSp","Parch","Fare","Embarked"]
## 选择 训练特征 数据
train_features = train_data[features]
## 选择 训练目标 数据
train_labels = train_data["Survived"]
## 选择 测试特征
test_features = test_data[features]
train_features
# 特征提取
"""
字典特征提取
Sex:
- male:0
- female:1
Embarked:
- S:1
- C:0
- Q:0
"""
from sklearn.feature_extraction import DictVectorizer
# 实例化
trans_d = DictVectorizer(sparse=False)
# 特征提取
# print(train_features) # 特征都是数组,而不是字典
data = train_features.to_dict(orient="record") # 转为字典
# print(data)
train_features = trans_d.fit_transform(data) # 特征都是数组,而不是字典
# 输出特征矩阵
print(train_features)
# 构建模型
from sklearn.tree import DecisionTreeClassifier
# 构建决策树
clf = DecisionTreeClassifier(criterion="entropy") # ID3算法
# 训练决策树 训练特征 训练目标
clf.fit(train_features,train_labels)
# 模型预测以及模型评估
## 测试集的特征值 转为 特征矩阵
test_features = trans_d.transform(test_features.to_dict(orient="record"))
## 决策树预测
pre_labels = clf.predict(test_features)
## 计算决策树的准确率
clf.score(train_features,train_labels)
# 交叉验证
"""
将数据集平均分割为k份
使用1份数据作为测试数据,其余的都作为训练数据
计算测试准确率
使用不同的测试集
"""
from sklearn.model_selection import cross_val_score
# 使用交叉验证,统计决策树的准确率
per_scores = cross_val_score(clf,train_features,train_labels,cv=10)
per_scores
# 求均值表示
np.mean(per_scores)
# 决策树可视化
"""
安装 graphviz 工具,这里是它的下载地址:http://www.graphviz.org/download/
将 graphviz 添加到环境变量PATH中
再通过pip install graphviz安装 graphviz 库
"""
from sklearn import tree
import graphviz
# 使用graphviz绘制决策树 生成dot
dot_data = tree.export_graphviz(clf,
filled = True,
rounded = True,
special_characters = True)
# 将dot数据进行可视化
graph = graphviz.Source(dot_data)
graph.render('tatanic')
graph
4.2 回归API
我们一般回归较少用决策树进行回归,简单以电影价为示例
from sklearn.datasets import load_boston
from sklearn.tree import DecisionTreeRegressor # 决策树回归API
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
boston = load_boston()
boston.feature_names
features = boston.data
prices = boston.target
train_feature,test_feature,train_price,test_price = train_test_split(features,prices,test_size=0.3)
dtr = DecisionTreeRegressor()
dtr.fit(train_feature,train_price)
predict_price = dtr.predict(test_feature)
predict_price
mean_squared_error(test_price, predict_price)