代码来自邹博老师的机器学习课程。其中对鸢尾花label转换为int,plt.pcolormesh()、决策树的可视化等方法都有一定的讲述。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import pydotplus
# 花萼长度、花萼宽度、花瓣长度、花瓣宽度
iris_feature_E = ['sepal length', 'sepal width', 'petal length', 'petal width']
iris_feature = ['花萼长度', '花萼宽度', '花瓣长度', '花瓣宽度']
iris_class = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
if __name__ == '__main__':
mpl.rcParams['font.family'] = 'SimHei'
mpl.rcParams['axes.unicode_minus'] = False
data = pd.read_csv('./iris.data', header=None)
x = data[[i for i in range(4)]]
y = pd.Categorical(data[4]).codes # 将obejet类型转化为int分类,得到numpy格式数据
# 为了可视化,仅使用前两列特征
x = x.iloc[:, :2]
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.7, random_state=1)
'''
决策树参数估计
1、分类用entropy或者gini,回归用mse
2、min_samples_split=10,如果该节点包含的样本数目大于10,则(有可能)对其分支 --看这一次
3、min_samples_leaf=10:若将某节点分支后,得到的每个子节点样本数目都大于10,则完成分支;否则不进行分支--看上一次
4、max_depth=1:树的深度,很重要
'''
model = DecisionTreeClassifier(criterion='entropy')
model.fit(x_train, y_train)
y_test_hat = model.predict(x_test)
print('测试集上的精确度:', np.mean(y_test == model.predict(x_test)))
#print(accuracy_score(y_hat, y_test))
# 保存
# 方法一:
with open('./iris.dot', 'w') as f:
tree.export_graphviz(model, f) # 可以下载个软件专门入去dot文件
'''
# 方法二:
tree.export_graphviz(model, './iris.dot')
'''
# 输出为PDF格式
dot_data = tree.export_graphviz(model, out_file=None, feature_names=iris_feature_E[:2],
class_names=iris_class,filled=True, rounded=True, special_characters=True)
# 这些参数是为了增添色彩效果
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_pdf('iris.pdf')
# 输出为png格式
f = open('iris.png', 'wb')
f.write(graph.create_png())
f.close()
# 画图
N, M = 50, 50 # 横纵各采样多少个值
x1_min, x2_min = x.min()
x1_max, x2_max = x.max()
t1 = np.linspace(x1_min, x1_max, N)
t2 = np.linspace(x2_min, x2_max, M)
x1, x2 = np.meshgrid(t1, t2) # 生成网格采样
x_show = np.stack([x1.flat, x2.flat], axis=1) # 和flatten()一样,但是这个好像是生成器,运行应该更快
# 将x1和x2分别转换为1列,然后横向拼接
#x_show = np.hstack([x1.flat, x2.flat]) 可以上代码是不一样的
cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
y_show_hat = model.predict(x_show) # 坐标预测值
y_show_hat = y_show_hat.reshape(x1.shape) # 使之与输入的形状相同
plt.figure(figsize=(12, 12))
plt.pcolormesh(x1, x2, y_show_hat, cmap=cm_light) # 坐标预测值的显示,画的是色块
plt.scatter(x_test[0], x_test[1], c=y_test.flat, edgecolors='k', s=150, zorder=10, cmap=cm_dark, marker='*')
plt.scatter(x[0], x[1], c=y.ravel(), edgecolors='k', s=40, cmap=cm_dark)
plt.xlabel(iris_feature[0], fontsize=15)
plt.ylabel(iris_feature[1], fontsize=15)
#plt.xlim(x1_min, x1_max)
#plt.ylim(x2_min, x2_max)
plt.grid()
plt.title('鸢尾花数据的决策树的分类', fontsize=18)
plt.show()
# 找到最优树的深度
depth = [i for i in range(1, 20)]
err_ls = []
for i in range(len(depth)):
model = DecisionTreeClassifier(max_depth=depth[i])
model.fit(x_train, y_train)
y_test_hat = model.predict(x_test)
accuracy = accuracy_score(y_test, y_test_hat)
error = 1 - accuracy
err_ls.append(error)
print(len(err_ls))
print(len(depth))
# 画图
plt.figure(figsize=(9, 6))
plt.plot(depth, err_ls, 'g-', lw=2)
plt.xlabel('树的深度', fontsize=12)
plt.ylabel('错误率', fontsize=12)
plt.xlim(min(depth)-1, max(depth)+1)
plt.xticks([i for i in range(int(min(depth)), int(max(depth)+2), 2)])
plt.title('鸢尾花数据决策树的深度和过拟合', fontsize=18)
plt.grid()
plt.legend()
plt.show()
在原图的基础上,绘制鸢尾花数据两两特征分别与目标值的关系。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
# 花萼长度、花萼宽度、花瓣长度、花瓣宽度
iris_feature_E = ['sepal length', 'sepal width', 'petal length', 'petal width']
iris_feature = ['花萼长度', '花萼宽度', '花瓣长度', '花瓣宽度']
iris_class = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
if __name__ == '__main__':
mpl.rcParams['font.family'] = 'SimHei'
mpl.rcParams['axes.unicode_minus'] = False
data = pd.read_csv('./iris.data', header=None)
_x = data[[i for i in range(4)]]
y = pd.Categorical(data[4]).codes # 将obejet类型转化为int分类,得到numpy格式数据
x_ls = [[0, 1], [0, 2], [0, 3], [1, 2], [1, 3], [2, 3]]
# 为了可视化,仅使用前两列特征
plt.figure(figsize=(12, 12))
num = 0
for i, j in x_ls:
x = _x.iloc[:, [i,j]] # 这里用_x,因为如果用x就会改变x报错。
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.7, random_state=1)
'''
决策树参数估计
1、分类用entropy或者gini,回归用mse
2、min_samples_split=10,如果该节点包含的样本数目大于10,则(有可能)对其分支 --看这一次
3、min_samples_leaf=10:若将某节点分支后,得到的每个子节点样本数目都大于10,则完成分支;否则不进行分支--看上一次
4、max_depth=1:树的深度,很重要
'''
model = DecisionTreeClassifier(criterion='entropy', max_depth=2)
model.fit(x_train, y_train)
y_test_hat = model.predict(x_test)
# 画图
num += 1
plt.subplot(2, 3, num)
N, M = 50, 50 # 横纵各采样多少个值
x1_min, x2_min = x.min()
x1_max, x2_max = x.max()
t1 = np.linspace(x1_min, x1_max, N)
t2 = np.linspace(x2_min, x2_max, M)
x1, x2 = np.meshgrid(t1, t2) # 生成网格采样
x_show = np.stack([x1.flat, x2.flat], axis=1) # 和flatten()一样,但是这个好像是生成器,运行应该更快
# 将x1和x2分别转换为1列,然后横向拼接
#x_show = np.hstack([x1.flat, x2.flat]) 可以上代码是不一样的
cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
y_show_hat = model.predict(x_show) # 坐标预测值
y_show_hat = y_show_hat.reshape(x1.shape) # 使之与输入的形状相同
plt.pcolormesh(x1, x2, y_show_hat, cmap=cm_light) # 坐标预测值的显示,画的是色块
plt.scatter(x_test[i], x_test[j], c=y_test.flat, edgecolors='k', s=80, zorder=10, cmap=cm_dark, marker='*')
plt.scatter(_x[i], _x[j], c=y.ravel(), edgecolors='k', cmap=cm_dark)
plt.xlabel(iris_feature[i], fontsize=15)
plt.ylabel(iris_feature[j], fontsize=15)
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
plt.grid()
plt.suptitle('决策树对鸢尾花数据的两两特征组合的分类结果', fontsize=18)
plt.tight_layout(1) # 子图各自间的间距
plt.subplots_adjust(top=0.92) # 总标题与第一行子图的距离
plt.show()