本文所用文件的链接
链接:https://pan.baidu.com/s/1RWNVHuXMQleOrEi5vig_bQ
提取码:p57s
关于决策树的初级应用,可以看我之前的文章:
https://blog.csdn.net/weixin_45081640/article/details/118056630
决策树分类
决策树分类模型会找到与样本特征匹配的叶子节点然后以投票的方式进行分类.
在car.txt样本文件中统计小汽车的常见特征信息及小汽车的分类, 使用这些数据可以预测小汽车的等级.
案例: car.txt 基于决策树分类,预测小汽车等级.
[['vhigh' 'vhigh' '2' ... 'small' 'low' 'unacc']
['vhigh' 'vhigh' '2' ... 'small' 'med' 'unacc']
['vhigh' 'vhigh' '2' ... 'small' 'high' 'unacc']
...
['low' 'low' '5more' ... 'big' 'low' 'unacc']
['low' 'low' '5more' ... 'big' 'med' 'good']
['low' 'low' '5more' ... 'big' 'high' 'vgood']]
(1728, 6) (1728,)
如上是数据的原型,数据的最后是汽车的等级,前面的数据是汽车的其他数据,训练的目的就是通过前面的数据来判断汽车的类别,即状态相似的类别相同。然后运行如下代码看下训练结果。
"""
预测小汽车的等级
"""
import numpy as np
import sklearn.preprocessing as sp
import sklearn.ensemble as se
import sklearn.model_selection as ms
data = np.loadtxt('../ml_data/car.txt',
dtype='U20', delimiter=',')
print(data)
data = data.T
encoders = []
train_x, train_y = [], []
for row in range(len(data)):
# 创建适用于当前特征的标签编码器
encoder = sp.LabelEncoder()
if row < len(data)-1:
train_x.append(
encoder.fit_transform(data[row]))
else:
train_y = \
encoder.fit_transform(data[row])
encoders.append(encoder)
train_x = np.array(train_x).T
# 模型训练
model = se.RandomForestClassifier(max_depth=6,
n_estimators=200, random_state=7)
# 交叉验证
print(train_x.shape, train_y.shape)
score = ms.cross_val_score(model, train_x,
train_y, cv=4, scoring='f1_weighted')
print(score.mean())
model.fit(train_x, train_y)
# 自定义测试集 进行预测
data = [
['high','med','5more','4','big','low','unacc'],
['high','high','4','4','med','med','acc'],
['low','low','2','4','small','high','good'],
['low','med','3','4','med','high','vgood']]
# 训练时如何做的标签编码, 测试时需要使用相同的
# 标签编码器进行编码
data = np.array(data).T
test_x, test_y = [], []
for row in range(len(data)):
encoder = encoders[row] # 得到标签编码器
if row < len(data)-1:
test_x.append(
encoder.transform(data[row]))
else:
test_y = encoder.transform(data[row])
test_x = np.array(test_x).T
pred_test_y = model.predict(test_x)
enc = encoders[-1]
print(enc.inverse_transform(test_y))
print(enc.inverse_transform(pred_test_y))
# 交叉验证得分
0.7465877061619401
# 检测四组数据,有一组错了。
['unacc' 'acc' 'good' 'vgood']
['unacc' 'acc' 'acc' 'vgood']
学习曲线
学习曲线: 模型性能 = f(训练集大小),通过学习曲线观察学习的效果。
_,train_score,test_score=ms.learning_curve(
model, 输入集, 输出集,
[0.9, 0.8, 0.7], # 训练集大小序列
cv=5 # 交叉验证折叠数
)
案例: 在小汽车评级案例中使用学习曲线选择训练集大小.
# 验证学习曲线 获取最优训练集大小
train_sizes = np.linspace(0.1, 1, 10)
_, train_scores, test_scores=ms.learning_curve(
model, train_x, train_y,
train_sizes=train_sizes, cv=5)
print(test_scores.mean(axis=1))
mp.figure('Learn Curve')
mp.title('Learn Curve', fontsize=16)
mp.xlabel('train size', fontsize=14)
mp.ylabel('score', fontsize=14)
mp.tick_params(labelsize=10)
mp.grid(linestyle=':')
mp.plot(train_sizes, test_scores.mean(axis=1),
linewidth=2, c='dodgerblue')
mp.show()
验证曲线
验证曲线: 模型性能(得分) = f(超参数)
什么是验证曲线
验证曲线是横轴为某个超参数的一系列值,由此来看不同参数设置下模型准确率,而不是不同训练集大小下的准确率。从验证曲线上可以看到随着超参数设置的改变,模型可能从欠拟合到合适再到过拟合的过程,进而选择一个合适的位置,来提高模型的性能。
需要注意的是如果我们使用验证分数来优化超参数,那么该验证分数是有偏差的,它无法再代表模型的泛化能力,我们就需要使用其他测试集来重新评估模型的泛化能力。
train_score,test_score=ms.validation_curve(
model, # 需要验证的模型对象
输入集, 输出集,
'n_estimators', # 需要进行测试的超参数名称
np.arange(50, 550, 50), #超参数选值
cv=5 # 折叠数
)
train_scores的结构:
超参数取值 | cv_1 | cv_2 | cv_3 | cv_4 | cv_5 |
---|---|---|---|---|---|
50 | 0.912 | 0.912 | 0.912 | 0.912 | 0.912 |
100 | 0.912 | 0.912 | 0.912 | 0.912 | 0.912 |
… | … | … | … | … | … |
通过验证曲线, 可以选择模型的较优超参数.
"""
验证曲线
"""
import numpy as np
import sklearn.preprocessing as sp
import sklearn.ensemble as se
import sklearn.model_selection as ms
import matplotlib.pyplot as mp
data = np.loadtxt('../ml_data/car.txt',
dtype='U20', delimiter=',')
data = data.T
encoders = []
train_x, train_y = [], []
for row in range(len(data)):
# 创建适用于当前特征的标签编码器
encoder = sp.LabelEncoder()
if row < len(data)-1:
train_x.append(
encoder.fit_transform(data[row]))
else:
train_y = \
encoder.fit_transform(data[row])
encoders.append(encoder)
train_x = np.array(train_x).T
# 模型训练
model = se.RandomForestClassifier(max_depth=6,
random_state=7)
# 输出验证曲线 选取最优:n_estimators
train_scores,test_scores=ms.validation_curve(
model, train_x, train_y,
'n_estimators', np.arange(50,550,50),
cv=5)
ne_scores = test_scores.mean(axis=1)
print(ne_scores)
mp.figure('VC')
mp.title('n_estimators Curve', fontsize=16)
mp.xlabel('n_estimators', fontsize=14)
mp.ylabel('score', fontsize=14)
mp.tick_params(labelsize=12)
mp.grid(linestyle=':')
mp.plot(np.arange(50,550,50), ne_scores,
linewidth=2, c='dodgerblue',
label='n_estimators Curve')
mp.legend()
mp.show()
model = se.RandomForestClassifier(
n_estimators=150, random_state=7)
# 输出验证曲线 选取最优:max_depth
train_scores,test_scores=ms.validation_curve(
model, train_x, train_y,
'max_depth', np.arange(1, 11),
cv=5)
md_scores = test_scores.mean(axis=1)
print(md_scores)
mp.figure('VC')
mp.title('max_depth Curve', fontsize=16)
mp.xlabel('max_depth', fontsize=14)
mp.ylabel('score', fontsize=14)
mp.tick_params(labelsize=12)
mp.grid(linestyle=':')
mp.plot(np.arange(1, 11), md_scores,
linewidth=2, c='orangered',
label='max_depth Curve')
mp.legend()
mp.show()
model = se.RandomForestClassifier(
max_depth=9, n_estimators=150,
random_state=7)
model.fit(train_x, train_y)
# 自定义测试集 进行预测
data = [
['high','med','5more','4','big','low','unacc'],
['high','high','4','4','med','med','acc'],
['low','low','2','4','small','high','good'],
['low','med','3','4','med','high','vgood']]
# 训练时如何做的标签编码, 测试时需要使用相同的
# 标签编码器进行编码
data = np.array(data).T
test_x, test_y = [], []
for row in range(len(data)):
encoder = encoders[row] # 得到标签编码器
if row < len(data)-1:
test_x.append(
encoder.transform(data[row]))
else:
test_y = encoder.transform(data[row])
test_x = np.array(test_x).T
pred_test_y = model.predict(test_x)
enc = encoders[-1]
print(enc.inverse_transform(test_y))
print(enc.inverse_transform(pred_test_y))
# 不同超参数的模型准确率:
[0.77959403 0.78654389 0.78885939 0.7853811 0.78654053 0.78828136
0.78828136 0.7853811 0.78770332 0.78769996]
[0.70023525 0.7094838 0.73147264 0.73438298 0.75986356 0.78885939
0.79176973 0.79584622 0.80855962 0.79177981]
# 最好的准确率测试的测试集结果,全对,完美的优化。
['unacc' 'acc' 'good' 'vgood']
['unacc' 'acc' 'good' 'vgood']