决策树是一种常用的机器学习算法,用于分类和回归任务。它通过学习简单的决策规则从数据特征中推断出目标值。以下是决策树的一些关键特点:
-
树形结构:决策树由一系列的问题组成,每个问题对应一个特征和可能的取值。这些问题按照树状结构组织,从根节点到叶节点,形成决策路径。
-
特征选择:在每个节点上,决策树算法会选择一个特征和阈值,将数据集分割成尽可能纯净的子集。这通常基于某种标准,如信息增益、基尼不纯度或均方误差。
-
递归分割:决策树通过递归地分割数据集来构建。在每个节点上,算法选择最佳特征进行分割,然后对每个子集重复这个过程,直到满足停止条件。
-
停止条件:决策树的构建过程会在满足特定条件时停止,例如:
- 达到预设的最大深度。
- 所有数据点都属于同一类别。
- 子集中的数据点数量小于某个阈值。
- 没有更多的特征可以用来进一步分割数据。
-
分类和回归:决策树可以用于分类任务(预测离散标签)和回归任务(预测连续值)。
-
可解释性:决策树模型易于理解和解释,因为它们可以被可视化为一系列的问题和答案。
-
过拟合风险:决策树容易过拟合,特别是当树很深或训练数据中的噪声较多时。为了防止过拟合,可以采用剪枝技术,如预剪枝(设置最大深度或最小分割样本数)或后剪枝(构建完整的树然后回溯删除不必要的节点)。
-
集成方法:为了提高性能和鲁棒性,可以使用集成方法,如随机森林或梯度提升决策树,这些方法通过结合多个决策树的预测来提高整体性能。
-
处理缺失值:决策树算法可以处理具有缺失值的特征,因为它们可以在每个节点上为缺失值选择不同的分支。
-
特征重要性:决策树可以评估特征对预测结果的重要性,这有助于特征选择和数据理解。
import numpy as np
from sklearn.tree import DecisionTreeClassifier
加载数据
import pandas as pd
y = np.array(list('NYYYYYNYYN'))
print(y)
X = pd.DataFrame({'日志密度':list('sslmlmmlms'),
'好友密度':list('slmmmlsmss'),
'真实头像':list('NYYYYNYYYY')})
X
可以看见如果直接使用模型的化会报错
数据转换
#代码只执行一次
X['日志密度'] = X['日志密度'].map({'s': 0, 'm': 1, 'l': 2})
X['好友密度'] = X['好友密度'].map({'s':0,'m':1,'l':2})
X['真实头像'] = X['真实头像'].map({'N':0,'Y':1})
X
建模和预测
model = DecisionTreeClassifier(criterion = 'entropy')
model.fit(X,y)
model.score(X,y)
对上面的决策树进行可视化
from sklearn import tree
import matplotlib.pyplot as plt
plt.rcParams['font.family'] ='FangSong'#字体
plt.figure(figsize=(12,16)) #图像大小
fn = X.columns #将DataFrame X 的列名赋值给变量 fn。
_=tree.plot_tree(model,filled=True,feature_names=fn)
plt.savefig('./决策树.png',dpi = 200)
手动计算决策树到底是如何实现分类的
p1 = (y =='N').mean()
p2 = (y =='Y').mean()
print(p1,p2)
p1 * np.log2(1/p1) +p2*np.log2(1/p2)
按照日志密度进行划分
X['真实用户'] = y
X
x = X['日志密度'].unique()
x.sort()#排序
print(x)
for i in range(len(x)-1):
split = x[i:i+2].mean()
#概率分布
cond = X['日志密度']<=split
#左边概率是多少,右边是多少
p = cond.value_counts()/cond.size
indexs = p.index
entropy = 0
for index in indexs:
user = X[cond ==index]['真实用户']#取出了目标值y的数据
p_user = user.value_counts()/user.size
#每个分支的信息熵
entropy += (p_user*np.log2(1/p_user)).sum()*p[index]
print(split,entropy)
#信息增益
0.881 - 0.6897
按照好友密度划分
x = X['好友密度'].unique()
x.sort()#排序
print(x)
for i in range(len(x)-1):
split = x[i:i+2].mean()
#概率分布
cond = X['好友密度']<=split
#左边概率是多少,右边是多少
p = cond.value_counts()/cond.size
indexs = p.index#True,False
entropy = 0
for index in indexs:
user = X[cond ==index]['真实用户']#取出了目标值y的数据
p_user = user.value_counts()/user.size
#每个分支的信息熵
entropy += (p_user*np.log2(1/p_user)).sum()*p[index]
print(split,entropy)
#信息增益
0.881-0.324
按照是否使用真实头像划分
x = X['真实头像'].unique()
x.sort()#排序
print(x)
for i in range(len(x)-1):
split = x[i:i+2].mean()
#概率分布
cond = X['真实头像']<=split
#左边概率是多少,右边是多少
p = cond.value_counts()/cond.size
indexs = p.index#True,False
entropy = 0
for index in indexs:
user = X[cond ==index]['真实用户']#取出了目标值y的数据
p_user = user.value_counts()/user.size
#每个分支的信息熵
entropy += (p_user*np.log2(1/p_user)).sum()*p[index]
print(split,entropy)
#信息增益
0.881-0.849
所以总结下来,看好友密度最能判断一个账户是否是真人