所有的详细步骤都在代码的注释里,这里就不单独列出来了
莺尾花数据就不放了评论区提取。
# 课程内容:
# 开发时间: 15:18
import warnings
import sys
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler,LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier,DecisionTreeRegressor#导入sklearn中构建决策树的包DecisionTreeClassifier(分类任务)DecisionTreeRegressor(回归任务)
from sklearn.metrics import auc,roc_curve,classification_report
"""
在python中运行代码经常会遇到的情况是——代码可以正常运行但是会提示警告,有时特别讨厌。
那么如何来控制警告输出呢?其实很简单,python通过调用warnings模块中定义的warn()函数来发出警告。我们可以通过警告过滤器进行控制是否发出警告消息。
"""
warnings.filterwarnings('ignore')
mpl.rcParams['font.sans-serif'] = [u'simHei']#解决正文乱码
"""一、加载数据"""
path = r'E:\机器学习课堂代码\代码\datas\iris.data'
names = ['A','B','C','D','cla']
df = pd.read_csv(filepath_or_buffer=path,sep=',',header=None,names=names)
#df.info()#用于打印DataFrame的简要摘要,显示有关DataFrame的信息,包括索引的数据类型dtype和列的数据类型dtype,非空值的数量和内存使用情况。
# print(df)
"""二、数据的清洗"""
# class_name_2_label = {'Iris-setosa': 0, 'Iris-versicolor': 1, 'Iris-virginica': 2}
# df['cla'] = list(map(lambda cla: class_name_2_label[cla], df['cla'].values))
# print(df['cla'].values)
# df.info()
"""三、根据需求和原始模型从最原始的特征属性中获取具体的特征属性矩阵X和目标属性矩阵Y"""
X = df.drop('cla',axis = 1)
X = np.asarray(X).astype(np.float64)
Y = df['cla']
## 对目标属性做一个类别的转换,将字符串的数据转换为从0开始的int值
lable_encoder = LabelEncoder()#创建对象,这个类可以用于解决上面的问题
Y = lable_encoder.fit_transform(Y)
# print(label_encoder.classes_)
# print(label_encoder.transform(['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']))
# print(label_encoder.inverse_transform([0, 1, 2, 0, 2, 1]))
# X.info()
"""# 四、数据分割(将数据分割为训练数据和测试数据) """
"""
我们使用sklearn进行机器学习之前,一般使用train_test_split来进行数据集的分割,其参数random_state代表什么呢?
可以看到,random_state默认状态下,两次分割的结果不一样
设置了random_state之后,两次分割的结果一样
结论: random_state的值相当于一种规则,通过设定为相同的数,每次分割的结果都是相同的
test_size:测试集所占的比例
"""
x_train,x_test,y_train,y_test = train_test_split(X,Y,test_size=0.2,random_state=28)#测试集比例为30%, random_state默认为28
print("训练数据X的格式:{}, 以及数据类型:{}".format(x_train.shape, type(x_train)))
print("测试数据X的格式:{}".format(x_test.shape))
print("训练数据Y的数据类型:{}".format(type(y_train)))
print("Y的取值范围:{}".format(np.unique(Y)))
"""五、特征工程的操作"""
"""同样用sklearn中的库进行特征工程"""
# # a. 创建对象(标准化操作)
# scaler = StandardScaler()
# # b. 模型训练+训练数据转换
# x_train = scaler.fit_transform(x_train, y_train)
# # c. 基于训练好的对象对数据做一个转换
# x_test = scaler.transform(x_test)
"""六、模型对象的构建"""
"""
def __init__(self,
criterion="gini",
splitter="best",
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.,
max_features=None,
random_state=None,
max_leaf_nodes=None,
min_impurity_decrease=0.,
min_impurity_split=None,
class_weight=None,
presort=False)
criterion: 给定决策树构建过程中的纯度的衡量指标,可选值: gini、entropy, 默认gini
splitter:给定选择特征属性的方式,best指最优选择,random指随机选择(局部最优)
注意,这里的best是向我们上一届构建决策树的时候一样,遍历所有分割的方式,找到信息增益度做大的分割方式
然而random随机选择,并不是随机选择一个特征进行分割,而是随机抽取N个特征,然后同best一样,只不过是遍历这50个特征,找出局部最优
这样做的好处大大降低了构建所消耗的时间。
max_features:当splitter参数设置为random的有效,是给定随机选择的局部区域有多大。
max_depth:剪枝参数,用于限制最终的决策树的深度,默认为None,表示不限制
实质上是提前停止了分裂操作,因为我们说过,对于训练集,如果不进行限制,一定可以达到100%的正确
这样的话树会很复杂,可能导致过拟合
min_samples_split=2:剪枝参数,给定当数据集中的样本数目大于等于该值的时候,允许对当前数据集进行分裂;如果低于该值,那么不允许继续分裂。
min_samples_leaf=1, 剪枝参数,要求叶子节点中的样本数目至少为该值。
减枝参数:一定程度上解决过拟合的问题
class_weight:给定目标属性中各个类别的权重系数。
"""
algo = DecisionTreeClassifier(criterion='entropy', max_depth=None, min_samples_leaf=1, min_samples_split=2)#创建一个模型
"""七、模型的训练"""
algo.fit(x_train,y_train)
"""八、模型的评估"""
"""
局册数对象有一个属性:algo.feature_importances_,表示的的是通过训练模型得到的每一个特征属性的重要程度的
类似于logistic回归,线性回归中每一个特征的θ
"""
print("各个特征属性的重要性权重系数(值越大,对应的特征属性就越重要):{}".format(algo.feature_importances_))
print("训练数据上的分类报告:")
print(classification_report(y_train, algo.predict(x_train)))
print("测试数据上的分类报告:")
print(classification_report(y_test, algo.predict(x_test)))
print("训练数据上的准确率:{}".format(algo.score(x_train, y_train)))
print("测试数据上的准确率:{}".format(algo.score(x_test, y_test)))
# 查看相关属性
test1 = [x_test[10]]
print("预测函数:")
print(algo.predict(test1))
print("预测概率函数:")
print(algo.predict_proba(test1))
print(algo.apply(test1))#这个数据在我们这棵树中最终落在拿一个叶子的节点上
"""九、决策树的可视化"""
# 方式一:输出dot文件,然后使用dot的命令进行转换
# 命令:dot -Tpdf iris.dot -o iris.pdf 或者dot -Tpng iris.dot -o iris.png
# from sklearn import tree
#
# with open('iris.dot', 'w') as writer:
# tree.export_graphviz(decision_tree=algo, out_file=writer)
# 方式二:直接使用pydotpuls库将数据输出为图像
import pydotplus
from sklearn import tree
import os
os.environ["PATH"] += os.pathsep + 'G:/program_files/graphviz/bin'
dot_data = tree.export_graphviz(decision_tree=algo, out_file=None,
feature_names=['A', 'B', 'C', 'D'],
class_names=['1', '2', '3'],
filled=True, rounded=True,
special_characters=True
)
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_png("iris0.png")
graph.write_pdf("iris0.pdf")
输出:
方式一输出:
对于这个输出方式:决策树的编号是从上往下,从左到右。根——>左——>右
这里我们做的是分类任务,最后的预测结果运用的是:多数表决法,比如
value = [0,35,3] 这个节点,第二类为35个,这个节点就被预测为第二类,有新数据进来时,如果通过决策树的遍历最后走到了这个节点,则被预测为第二类
如果做回归任务,这38条数据的平均值就是该节点代表的值。
方式二输出: