搜索
您的当前位置:首页正文

机器学习——sklearn实现决策树

来源:知库网

导入包和数据集

# 导入包
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

信息熵实现

熵来自于热力学系统,熵越大,粒子运动越剧烈,不规则性越大;反之亦然。在信息论中代表不确定的度量

  • 信息熵越大,不确定性越大
  • 信息熵越小,不确定性越小

计算公式:
二分类问题:

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 Treesklearn中的默认方式

  • 预测: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
Top