决策树和随机森林
1.决策树
(1)决策树是一个有监督的机器学习算法,做分类用的,而且是非线性的。
决策树是通过固定的条件来对类别进行判断:
(2)决策树的建模过程,不是创造一个方程了,而是构建一棵树。这棵树不一定只是二叉树
决策树的生成:数据在不断分裂的递归过程,每一次分裂,尽可能让类别一样的数据在树的一边,
当树的叶子节点的数据都是一类的时候,则停止分裂(if lese语句)
计算纯度的方式
损失函数:
- 基尼系数:
基尼系数是指国际上通用的、用以衡量一个国家或地区居民收入差距的常用指标。
若低于0.2表示指数等级极低;(高度平均)
0.2-0.29表示指数等级低;(比较平均)
0.3-0.39表示指数等级中;(相对合理)
0.4-0.59表示指数等级高;(差距较大)
0.6以上表示指数等级极高。(差距悬殊) - 熵
- 方差
这三种,都是值越大,纯度越高
纯度:当我们应用一个特征(比如说头发长度)对数据(男女)进行分类的时候,如果这个特征能把数据都分到一边去(全部男,或者全部女),我们就说这个特征可分类的纯度高
有很多参数都在围绕纯度进行调式:splitter (best, random).....
(4) 决策树的参数:都是为了构建一个优秀的决策树,提供的支持
max_leaf_node, max_depth…
案例:鸢尾花。
具体代码实现:
"""
Date: 2019--11 09:41
User: yz
Email: 1147570523@qq.com
Desc:
"""
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
# 决策树分类器
from sklearn.tree import DecisionTreeClassifier
# 分割训练集和测试集的比例
from sklearn.model_selection import train_test_split
# metrics做评估用的, accuracy_score是为了评估准确率
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
iris = load_iris()
data = pd.DataFrame(iris.data)
data.columns = iris.feature_names
data['Species'] = iris.target
pd.set_option('display.max_columns', 1)
x = data.iloc[:, :2] # 花萼长度和宽度
y = data.iloc[:, -1]
# train_size切分数据集的比例 random_state随机种子,保证每次切割的数据集都是一模一样的
x_train, x_test, y_train, y_test = train_test_split(x, y, train_size=0.75, random_state=42)
# 创建一个决策树的模型,最大深度max_depth是2, 求纯度的分割标准criterion,默认的是基尼系数gini,这里是entropy标准
tree_clf = DecisionTreeClassifier(max_depth=2, criterion='entropy')
tree_clf.fit(x_train, y_train)
y_test_hat = tree_clf.predict(x_test)
print("acc score:", accuracy_score(y_test, y_test_hat))
depth = np.arange(1, 15)
err_list = []
for d in depth:
# splitter: best 找最好的维度进行分裂 random随机找维度进行分裂
# max_feature: 找最好分割维度的时候,找多少个特征 none就是不限制找的数量 int就是找3个进行考量 float就是找0.5(50%)去试 sqrt就是找所有特征开根号个特征
# max_depth: 最大深度 None的话,得看 min_sample_split
# min_sample_split: 分裂前我需要保证这个叶子有几个样本 int就是直接取, float还是要计算一下
# min_samples_leaf: 分类后需要保证每个分裂的叶子有几个样本(min_sample_split=2, min_samples_leaf=1)
# min_weight_fraction_leaf 每个叶子节点里的样本数,必须是所有样本的10%
# max_leaf_nodes: 最多的叶子数
# min_impurity_split: 每一个叶子节点里面的不纯度,最小保证多纯:保证不会过早的停止生长;达不到指标就继续往下分
clf = DecisionTreeClassifier(criterion='entropy', max_depth=d)
clf.fit(x_train, y_train)
y_test_hat = clf.predict(x_test)
result = (y_test_hat == y_test)
err = 1 - np.mean(result)
err_list.append(err)
print(d, '错误率: %.2f%%' % (100 * err))
# 图的底色
plt.figure(facecolor='w')
# ro- red 圈 横线连起来
plt.plot(depth, err_list, 'ro-', lw=2)
plt.xlabel('Decision Tree Depth', fontsize=15)
plt.ylabel('Error Rate', fontsize=15)
plt.title('Decision Tree Depth & Over Fit', fontsize=18)
plt.grid(True)
plt.show()
(5)剪枝:就是决策数的正则化
为了减少过拟合的现象
预剪枝:在树没有生成前,通过对将要生成树的判断,来进行限制max_depth
后剪枝:在树生成之后,通过对某些叶子节点的删除,来进行限制max_leaf_perc
单颗决策树的缺点:
运算量大,需要一次加载所有数据进内存。并且找寻分割条件是一个极耗资源的工作
训练样本中出现异常数据时,将会对决策树产生很大影响。抗干扰能力差
解决方法:
减少决策树所需训练样本(减少列或者减少行)
随机采样,降低异常数据的影响
逻辑回归的优点:
和逻辑回归比,逻辑回归可以给告诉我们概率(或者设置阈值),二决策树只能0, 1
用决策树做回归。
具体代码实现:
"""
Date: 2019--10 16:56
User: yz
Email: 1147570523@qq.com
Desc:
"""
import numpy as np
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt
N = 100
x = np.random.rand(N) * 6 - 3
x.sort()
y = np.sin(x) + np.random.rand(N) * 0.05
x = x.reshape(-1, 1)
dt_reg = DecisionTreeRegressor(criterion='mse', max_depth=3)
dt_reg.fit(x, y)
x_test = np.linspace(-3, 3, 50).reshape(-1, 1)
y_hat = dt_reg.predict(x_test)
plt.plot(x, y, "y*", label="actual")
plt.plot(x_test, y_hat, "b-", linewidth=2, label="predict")
plt.legend(loc="upper left")
plt.grid()
plt.show()
#################################################
# 比较不同深度的决策树
depth = [2, 4, 6, 8, 10]
color = 'rgbmy'
dt_reg = DecisionTreeRegressor()
plt.plot(x, y, "ko", label="actual")
x_test = np.linspace(-3, 3, 50).reshape(-1, 1)
for d, c in zip(depth, color):
dt_reg.set_params(max_depth=d)
dt_reg.fit(x, y)
y_hat = dt_reg.predict(x_test)
plt.plot(x_test, y_hat, '-', color=c, linewidth=2, label="depth=%d" % d)
plt.legend(loc="upper left")
plt.grid(b=True)
plt.show()
2. 随机森林
随机森林,就是由很多决策树构成的。当数据集很大的时候,我们随机选取数据集的一部分,生成一颗树,重复上述过程,我们可以生成一堆形态各异的树,这些树放在一起就叫森林。
(1)并行思想:因为随机森林中的树都是相互独立的,所以这些树可以在不同的机器上,或者CPU,GPU上运行
这样能极大缩短建模的时间
随机森林VS逻辑回归
随机森林代码实现:
"""
Date: 2019--12 10:52
User: yz
Email: 1147570523@qq.com
Desc:
"""
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data[:, :2] # 花萼的长度和宽度(因为选花瓣的长宽的话,分类效果太好了)
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=43)
# n_estimators指的是用多少颗树, max_leaf_1des指树的复杂程度, n_jobs指用多少个线程
rnd_clf = RandomForestClassifier(n_estimators=30, max_leaf_nodes=16, n_jobs=1)
rnd_clf.fit(X_train, y_train)
# bagging:并行思想,bagging的决策树和随机森林其实是等价的
# max_samples 训练时用所有的样本 splitter=random 指的是虽然每课小树取使用所有样本,但是我只使用随机出来的一部分维度来训练每棵小树
bag_clf = BaggingClassifier(
DecisionTreeClassifier(splitter="random", max_leaf_nodes=16),
n_estimators=30, max_samples=1.0, bootstrap=True, n_jobs=1
)
bag_clf.fit(X_train, y_train)
y_pred_rf = rnd_clf.predict(X_test)
y_pred_bag = bag_clf.predict(X_test)
print(accuracy_score(y_test, y_pred_rf))
print(accuracy_score(y_test, y_pred_bag))
# Feature Importance 用随机森林选择出来重要的特征,也就是分裂效果好的特征,也就是和y相关性大的特征
# 一般来说,相关性越大的特征,应该出现在树的上层
iris = load_iris()
# -1 表示有多少线程用多少线程
rnd_clf = RandomForestClassifier(n_estimators=500, n_jobs=-1)
rnd_clf.fit(iris["data"], iris['target'])
for name, score in zip(iris['feature_names'], rnd_clf.feature_importances_):
print(name, score)