导入包和数据集
# 导入包
import numpy as np
import matplotlib.pyplot as plt
# 导入数据,生成相应的输入数据和输出数据集
from sklearn import datasets
iris = datasets.load_iris()
# 全部行,保留后两个特征,总共4个特征
X = iris.data[:, 2:]
y = iris.target
查看数据的相关信息
# 查看数据集的具体信息
iris.keys()
# dict_keys(['data', 'target', 'target_names', 'images', 'DESCR'])
# 查看样本信息
Z = iris.data
Z.shape
# 查看输出实例信息
y = iris.target
y.shape
# 查看输出的具体信息
iris.target_names
image.png
绘图
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.scatter(X[y==2, 0], X[y==2, 1])
plt.show()
image.png
调用sklearn
# 导入决策树包
from sklearn.tree import DecisionTreeClassifier
# 创建实例,传入两个参数:树的最大深入和特征判断的标准即信息熵
dt_clf = DecisionTreeClassifier(max_depth=2, criterion='entropy')
# 拟合过程,返回拟合结果
dt_clf.fit(X, y)
# 模型的决策边界创建
def plot_decision_boundary(model, axis):
# meshgrid,linspace,reshape
x0, x1 = np.meshgrid(
np.linspace(axis[0], axis[1], int((axis[1] - axis[0])*100)).reshape((70,10)),
np.linspace(axis[2], axis[3], int((axis[3] - axis[2])*100)).reshape((30,10))
)
X_new = np.c_[x0.ravel(), x1.ravel()]
y_predict = model.predict(X_new)
z = y_predict.reshape(x0.shape)
# 自定义图形的颜色元素
from matplotlib.colors import ListedColormap
custom_camp = ListedColormap(['#EF9A9A', '#FFF59D', '#90CAF9'])
plt.contourf(x0, x1, z, linewidth=5, cmap=custom_camp)
plot_decision_boundary(dt_clf, axis=[0.5, 7.5, 0, 3])
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.scatter(X[y==2, 0], X[y==2, 1])
plt.show()
image.png
信息熵实现
熵来自于热力学系统,熵越大,粒子运动越剧烈,不规则性越大;反之亦然。在信息论中代表不确定的度量
- 信息熵越大,不确定性越大
- 信息熵越小,不确定性越小
计算公式:
二分类问题:
结果
当样本的分类中只有两个类别,且当它们的占比都为0.5时
- 占比为0.5时,不确定性最高,即熵最大
- 当x变大或者变小的时候,更加偏向于某个类,确定性都会提高,信息熵都会变小
- 当每个类别是等概率的时,不确定性最高
使用信息熵寻找最优划分
# d:节点维度,value:阈值
def split(X, y, d, value):
# 左、右两边阈值
index_a = (X[:,d] <= value)
index_b = (X[:,d] > value)
# 返回的是分成的两类数据
return X[index_a], X[index_b], y[index_a], y[index_b]
from collections import Counter
from math import log
def entropy(y):
counter = Counter(y)
res = 0.0
for num in counter.values():
p = num / len(y)
res += -p * log(p)
return res
def try_split(X, y):
# 目的是为了找出信息熵更小的值,找出更好的则更新best_entropy
best_entropy = float("inf")
best_d, best_v = -1, -1
# 对X的维度进行穷搜遍历
for d in range(X.shape[1]):
sorted_index = np.argsort(X[:, d])
for i in range(1, len(X)):
if X[sorted_index[i-1], d] != X[sorted_index[i], d]:
v = (X[sorted_index[i-1], d] + X[sorted_index[i], d]) / 2
x_l, x_r, y_l, y_r = split(X, y, d, v)
e = entropy(y_l) + entropy(y_r)
if e < best_entropy:
best_entropy, best_d, best_v = e, d, v
return best_entropy, best_d, best_v
image.png
image.png
基尼系数
计算公式:
在sklearn中默认使用的是基尼系数进行决策树的划分
from collections import Counter
from math import log
# d:节点维度,value:阈值
def split(X, y, d, value):
# 左、右两边阈值
index_a = (X[:,d] <= value)
index_b = (X[:,d] > value)
# 返回的是分成的两类数据
return X[index_a], X[index_b], y[index_a], y[index_b]
def gini(y):
# 变成字典形式
counter = Counter(y)
res = 1.0
for num in counter.values():
p = num / len(y)
# 公式中用1-p**2, 不断地遍历
res += -p ** 2
return res
def try_split(X, y):
# 目的是为了找出基尼系数更小的值,找出更好的则更新best_g
best_g = float("inf")
best_d, best_v = -1, -1
# 对X的每个特征进行遍历
for d in range(X.shape[1]):
# 每个特征维度上进行排序
sorted_index = np.argsort(X[:, d])
# 对每个样本进行遍历
for i in range(1, len(X)):
# 在维度d上,相邻两个样本的值不等,二者均值为搜索的v
if X[sorted_index[i-1], d] != X[sorted_index[i], d]:
v = (X[sorted_index[i-1], d] + X[sorted_index[i], d]) / 2
# 利用当前的d,v进行split方法
x_l, x_r, y_l, y_r = split(X, y, d, v)
e = gini(y_l) + gini(y_r)
if e < best_g:
best_g, best_d, best_v = e, d, v
return best_g, best_d, best_v
image.png
CART和超参数
Classification And Regression Tree
是sklearn
中的默认方式
- 预测:O(logm)
- 训练:O(nmlogm)
剪枝的作用是:降低复杂度和防止过拟合
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
# 使用的虚拟数据
X, y = datasets.make_moons(noise=0.15, random_state=666)
# X[y==0, 0]:找出当y取值为0时,X的第一个值(索引为0)
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.show()
image.png
from sklearn.tree import DecisionTreeClassifier
dt_clf = DecisionTreeClassifier()
dt_clf.fit(X, y)
# 模型的决策边界创建
def plot_decision_boundary(model, axis):
# meshgrid,linspace,reshape
x0, x1 = np.meshgrid(
np.linspace(axis[0], axis[1], int((axis[1] - axis[0])*100)).reshape((40,10)),
np.linspace(axis[2], axis[3], int((axis[3] - axis[2])*100)).reshape((10,25))
)
X_new = np.c_[x0.ravel(), x1.ravel()]
y_predict = model.predict(X_new)
z = y_predict.reshape(x0.shape)
# 自定义图形的颜色元素
from matplotlib.colors import ListedColormap
custom_camp = ListedColormap(['#EF9A9A', '#FFF59D', '#90CAF9'])
plt.contourf(x0, x1, z, linewidth=5, cmap=custom_camp)
plot_decision_boundary(dt_clf, axis=[-1.5, 2.5, -1.0, 1.5])
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.show()
image.png
调节参数
# 传入参数max_depth=2
dt_clf = DecisionTreeClassifier(max_depth=2)
dt_clf.fit(X ,y)
plot_decision_boundary(dt_clf, axis=[-1.5, 2.5, -1.0, 1.5])
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.show()
image.png
决策树应用于回归问题:波士顿房价
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
boston = datasets.load_boston()
X = boston.data
y = boston.target
from sklearn.model_selection import train_test_split
# 进行数据的分割
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
from sklearn.tree import DecisionTreeRegressor
dt_reg = DecisionTreeRegressor()
dt_reg.fit(X_train, y_train)
# 在测试数据集上的准确率不高
dt_reg.score(X_test, y_test) # 0.58
# 训练数据集上100%准确,在测试数据集上不好,说明出现过拟合现象
dt_reg.score(X_train, y_train) # 1
网格搜索
from sklearn.tree import DecisionTreeRegressor
dt_reg = DecisionTreeRegressor()
dt_reg.fit(X_train, y_train)
# 利用网格搜索进行调参,一定要注意每个参数的起始值
para_grid = [
{
"max_depth": [i for i in range(1, 10)],
"max_leaf_nodes": [i for i in range(2, 10)],
"min_samples_split": [i for i in range(2,10)],
"max_features": [i for i in range(1, 10)]
}
]
# 导入调参的包,传入实例和设置的参数
from sklearn.model_selection import GridSearchCV
# 创建实例
grid_search = GridSearchCV(dt_reg, para_grid)
%%time
grid_search.fit(X_train, y_train)
image.png