什么是决策树算法?
决策树本质是一种树结构,预测时,在树的内部节点处用某一属性值进行判断,根据判断结果决定进入哪个分支节点,直到到达叶节点处,得到分类结果。本质上就是不断进行 if ... else ... 判断。
比如,一位女士,28 岁,未婚,过年回家被妈妈介绍相亲。
对话1
妈妈:给你介绍一位男士。
女儿:长相如何?
妈妈:耐看型,不算丑。
女儿:性格怎么样?
妈妈:不好。
女儿:不见。
对话2
妈妈:给你介绍一位男士。
女儿:长相如何?
妈妈:耐看型,不算丑。
女儿:收入如何?
妈妈:very OK.
女儿:见。
以上决策的过程就是决策树的原理。
决策依据包括长相、收入、性格、职位。决策结果为见或不见。
当这种对话多进行几轮后,我们就可以大致判断出哪些因素对结果影响较大,比如收入高或者职位是公务员更加受青睐,而其他因素影响甚微。那么,程序如何选择条件判断的先后次序呢?
决策树分类原理:熵
系统越有序,熵值越低;系统越混乱或者分散,熵值越高。
在信息论中,熵是表示随机变量Y的不确定性的度量。假设类别Y是一个离散随机变量,其概率分布为p1,p2,...,pK,那么Y的熵被定义为:
一般,对数取以2为底。
例如:
足球比赛里,有4个球队 {A,B,C,D} ,获胜概率分别为{1/2, 1/4, 1/8, 1/8},求H(X)。
信息增益
信息增益:以某特征划分数据集前后的熵的差值。熵可以表示样本集合的不确定性,熵越大,样本的不确定性就越大。因此可以使用划分前后集合熵的差值来衡量使用当前特征对于样本集合D划分效果的好坏。
G(D|A)=H(D)-H(D|A)
信息熵:
条件熵:
Ck表示某个类别的样本数。
例如:
第一列为论坛号码,第二列为性别,第三列为活跃度,最后一列用户是否流失。
那么性别和活跃度两个特征,哪个对用户流失影响更大?
整体熵:
性别熵:
性别信息增益:
活跃度熵:
活跃度信息增益:
Python程序实战
预测波士顿房屋价格
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import sklearn.model_selection as ms # 模型选择
import sklearn.svm as svm
import sklearn.metrics as sm
import sklearn.tree as st #决策树
# 读取数据
data = pd.read_csv('./HousingData.csv')
y = data['MEDV']
x = data.drop('MEDV', axis=1)
train_x, \
test_x, \
train_y, \
test_y = ms.train_test_split(x, y,#待划分数据
test_size=0.2,#测试集占比
random_state=7)#随机种子
#单棵决策树回归
model = st.DecisionTreeRegressor(max_depth=4)
model.fit(train_x,train_y)
pred_train_y = model.predict(train_x)
pred_test_y = model.predict(test_x)
print('单棵数训练集:',sm.r2_score(train_y,pred_train_y))
print('单棵数测试集:',sm.r2_score(test_y,pred_test_y))
#特征重要性
fi = model.feature_importances_
print(fi)
# print(fi.sum())
fi = pd.Series(fi)
fi = fi.sort_values(ascending=False)
print(fi)
#决策树可视化
st.plot_tree(model)
plt.show()
集成学习
梯度提升决策树(GBDT Gradient Boosting Decision Tree) 是一种迭代的决策树算法,该算法由多棵决策树组成,所有树的结论累加起来做最终答案。它在被提出之初就被认为是泛化能力(generalization)较强的算法。
# 删除缺失值
data = data.dropna()
#构建模型
sub_model = st.DecisionTreeRegressor(max_depth=6)
model = se.AdaBoostRegressor(sub_model,
n_estimators=400,
random_state=7)
model.fit(train_x,train_y)
pred_train_y = model.predict(train_x)
pred_test_y = model.predict(test_x)
print('训练集:',sm.r2_score(train_y,pred_train_y))
print('测试集:',sm.r2_score(test_y,pred_test_y))
输出:
训练集: 0.985593080950688
测试集: 0.9264863823619695