QuickReference/source/_posts/machinelearning/decisiontree.md

214 lines
8.2 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 决策树算法
tags: decisiontree
categories: machinelearning
abbrlink: 95
date: 2025-01-24 12:39:59
cover: https://th.bing.com/th/id/OIP.XaPUn6eccfS_z_wTLQNFzgHaEK?w=240&h=180&c=7&r=0&o=5&dpr=1.9&pid=1.7
---
### C4.5
C4.5 是一种用于生成决策树的算法,不再使用信息增益,而是使用信息增益比,来避免偏向于选择取值较多的特征。信息增益比是信息增益与特征的熵的比值。
### ID3
D3 是一种基于信息增益Information Gain的决策树算法
### Cart
CART分类与回归树一种决策树算法CART 使用 **二叉树结构**,即每个节点只能有两个子节点。
### cart剪枝
CART 决策树的剪枝方法分为 **预剪枝**Pre-pruning**后剪枝**Post-pruning两种
#### **预剪枝**
预剪枝是在构建决策树时就决定是否停止进一步划分某个节点。主要通过以下标准来控制:
- 当某个节点的样本数小于某个阈值时,不再继续划分。
- 当某个节点的 Gini 不纯度小于某个阈值时,不再继续划分。
预剪枝的优点是能够减少计算量,但缺点是可能会导致模型不够复杂,从而产生欠拟合。
#### **后剪枝**
后剪枝是在决策树完全构建出来之后,对树进行修剪。具体过程如下:
- 构建完整的决策树。
- 从叶子节点开始,逐渐向上遍历树的每个节点。
- 对每个节点进行判断,是否合适剪去该节点及其子树。如果剪去该子树后,模型的性能没有显著下降,就可以剪枝。
后剪枝通过避免过度拟合来提高模型的泛化能力,但其计算开销较大。
### 特征工程(特征提取)
- **字典特征提取**
主要用于处理包含键值对key-value pairs的数据结构
   ```python
   from sklearn.feature_extraction import DictVectorizer
   # 字典特征提取
   data = [
       {'city': 'beijing', 'temperature': 100},
       {'city': 'shanghai', 'temperature': 95},
       {'city': 'guangzhou', 'temperature': 98}
   ]
   transfer = DictVectorizer(sparse=False)
   new_data = transfer.fit_transform(data)
   print(transfer.feature_names_)
   print(new_data)
   ```
- **文本特征提取**
主要用于将文本数据(如句子、段落、文章等)转换成数值型特征。这对于文本分类、信息检索等任务非常重要。
   ```python
   from sklearn.feature_extraction.text import CountVectorizer
   # 示例文本数据
   data = [
       "I love programming",
       "Python is great",
       "I love machine learning"
   ]
   # 创建 CountVectorizer 对象
   transfer = CountVectorizer()
   # 将文本数据转换为特征向量
   new_data = transfer.fit_transform(data)
   # 输出特征名称
   print("Feature Names:", transfer.get_feature_names_out())
   # 输出转换后的特征矩阵
   print("Transformed Data:", new_data.toarray())
   ```
- 文本特征提取(中文文本)
```python
  from sklearn.feature_extraction.text import CountVectorizer
  import jieba
  # 中文文本数据大于20个字
  data = [
    "我热爱编程,学习编程语言是一件非常有趣的事情,它能够提升我们解决问题的能力,编程让我变得更加有创意。",
    "Python语言是一门非常强大的编程语言具有简洁的语法和丰富的库可以帮助开发者更高效地完成任务。",
    "机器学习是一项非常有前途的技术,它能够让计算机从数据中自动学习,逐步提高模型的精确度,解决实际问题。"
  ]
  # 使用jieba分词
  text_list = []
  for line in data:
    text_list.append(" ".join(list(jieba.cut(line))))
  # 创建 CountVectorizer 对象
  transfer = CountVectorizer()
  # 将文本数据转换为特征向量
  new_data = transfer.fit_transform(text_list)
  # 输出特征名称
  print("Feature Names:", transfer.get_feature_names_out())
  # 输出转换后的特征矩阵
  print("Transformed Data:", new_data.toarray())
```
### tf-idf
> 词频 * 逆文档频率
```python
# tfi-df
from sklearn.feature_extraction.text import TfidfVectorizer
import jieba
data=["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
"我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去",
"如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系"]
list = []
for item in data:
list.append(" ".join(jieba.cut(item)))
transfer = TfidfVectorizer()
new_data = transfer.fit_transform(list)
print(f"特征名字:\n{transfer.get_feature_names_out()}")
print(f"转换后的特征矩阵:\n{ new_data.toarray()}")
print(f"转换后的数据:\n{new_data}")
```
### 回归决策树
#### 决策树算法的应用 (泰坦尼克号沉船幸存者预测)
```python
import seaborn as sns
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer
from sklearn.tree import DecisionTreeClassifier,export_graphviz
# 1.获取数据集 - 加载 Titanic 数据集
titanic = sns.load_dataset('titanic')
missing_age_count = titanic['age'].isna().sum()
# print(f"缺失的 age 数量: {missing_age_count}")
# 2. 数据基本处理
# 2.1 确认特征值、目标值
X = titanic[['pclass','age','sex']]
y = titanic['survived']
# 2.2 缺失值处理
X.loc[:, 'age'] = X['age'].fillna(value=X['age'].mean()) # 使用 .loc 进行修改
# 2.3 划分数据集
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=22)
# 3. 特征工程(字典特征提取)
X_train = X_train.to_dict(orient="records")
X_test= X_test.to_dict(orient="records")
transfer = DictVectorizer()
X_train = transfer.fit_transform(X_train)
X_test = transfer.transform(X_test)
# 4. 机器学习 决策树算法
estimator = DecisionTreeClassifier(criterion="gini")
estimator.fit(X_train,y_train)
y_pred = estimator.predict(X_test)
print(f"模型的测试集的预测值:{y_pred}")
ret = estimator.score(X_test,y_test)
print(f"模型的评分:{ret}")
print(X_test.toarray())
```
生成对应的图
```python
from sklearn.tree import export_graphviz
import graphviz # 用于渲染图像
# 导出决策树的 Graphviz 表示
export_graphviz(estimator, out_file='./data/tree.dot',
feature_names=transfer.get_feature_names_out()) # 特征名称
# 使用 graphviz 渲染 .dot 文件
with open('./data/tree.dot', 'r') as f:
dot_graph = f.read()
# 渲染决策树
graph = graphviz.Source(dot_graph)
# 设置保存路径
output_path = './data/decision_tree' # 自定义保存路径
# 保存图像到指定路径,格式可以是 .png, .pdf, .jpg 等
# graph.render(output_path, format='png') # 保存为 .png 文件
# 显示图像
graph.view(output_path) # 打开图像path为保存路径不需要加后缀
```
[Webgraphviz](http://webgraphviz.com/),这个网站可以将`tree.dot`文件的内容生成对应的可视化树
#### 回归决策树与线性回归的对比
```python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from matplotlib import rcParams
# 设置matplotlib使用的字体为SimHei黑体
rcParams['font.sans-serif'] = ['SimHei'] # 也可以使用 'Microsoft YaHei'
rcParams['axes.unicode_minus'] = False # 正常显示负号
x = np.array(list(range(1,11))).reshape(-1,1)
y = ([5.56,5.70,5.91,6.40,6.80,7.05,8.90,8.70,9.00,9.05])
m1 = DecisionTreeRegressor(max_depth=1)
m2 = DecisionTreeRegressor(max_depth=3)
m3 = DecisionTreeRegressor()
# 模型训练
m1.fit(x,y)
m2.fit(x,y)
m3.fit(x,y)
# 模型预测
x_test = np.arange(0,10,0.01).reshape(-1,1)
y_1 = m1.predict(x_test)
y_2 = m2.predict(x_test)
y_3 = m3.predict(x_test)
# 结果展示
plt.figure(figsize=(10,6),dpi=100)
plt.scatter(x,y ,label = "data")
plt.plot(x_test,y_1,label = "max_depth=1")
plt.plot(x_test,y_2,label = "max_depth=3")
plt.plot(x_test,y_3,label = "linearregression")
plt.xlabel("数据")
plt.ylabel("预测值")
plt.legend()
plt.show()
```