Python使用“决策树”算法解决预测钻石成本的问题

发布于:2025-03-31 ⋅ 阅读:(13) ⋅ 点赞:(0)

任务

我们的任务是训练一个基于决策树的标准回归器,以解决根据一组特征预测钻石成本的问题,这些特征包括:克拉数、颜色、净度、几何尺寸等。

你可以从这里找到数据集

在做之前,我们要看下数据集是什么样子?
在这里插入图片描述

观察后我们发现必须对数据集进行如下预处理:

  • 删除重复索引的不必要的列;
  • 将所有数据转换为数字类型(如有必要)*;
  • 使用 One-hot 编码器来转换分类特征。在我们的案例中,分类特征是"cut", “color” и “clarity”;
  • 使用 sklearn.utils.shuffle 函数和 random_state=42 对样本进行打乱。

然后,我们用多个建议的超参数组合中选择最佳组合:

  • 分支标准:squared_error,树深度:12
  • 分支标准:friedman_mse,树深度:16
  • 分支标准:possion,树深度:22
  • 分支标准:squared_error,树深度:45
  • 分支标准:friedman_mse,树深度:95
  • 分支标准:possion,树深度:33

解决

1. 导入必要的库

import pandas as pd
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeRegressor
from sklearn.utils import shuffle
from sklearn.preprocessing import LabelEncoder
  • cross_val_scoresklearn 中用于进行交叉验证并计算模型得分的函数。
  • DecisionTreeRegressorsklearn 中用于实现决策树回归模型的类。
  • shuffle 函数用于打乱数据集的顺序。
  • LabelEncoder 用于将分类变量编码为整数。

2. 加载数据

# 加载数据
data = pd.read_csv('/content/TRAIN.csv')

3. 数据预处理

# 数据预处理
data = data.drop(data.columns[0], axis=1) # 删除重复索引列(第一列为没用的索引列)
# data = data.drop(columns=['unnecessary_column'])  # 或使用方法指定删除不必要的列
data = shuffle(data, random_state=42)  # 打乱样本
  • data.drop(data.columns[0], axis=1):删除 DataFrame 的第一列,通常用于去除重复的索引列。axis=1 表示按列操作。
  • shuffle(data, random_state=42):打乱数据集的顺序,random_state=42 用于确保每次运行代码时打乱的顺序相同,方便结果的复现。

4. 转换类别型特征

# 转换类别型特征(这是文本需要转化成数字参数的部分)
categorical_features = ['cut', 'color', 'clarity']
label_encoders = {col: LabelEncoder() for col in categorical_features}
for col in categorical_features:
    data[col] = label_encoders[col].fit_transform(data[col])
  • categorical_features:定义了需要进行编码的类别型特征的列名列表。
  • label_encoders:使用字典推导式创建一个字典,键为列名,值为对应的 LabelEncoder 对象。
  • LabelEncoder 是 scikit-learn 库中的一个类,它的主要作用是将分类标签(即文本形式的类别)转换为整数编码。每个不同的类别会被赋予一个唯一的整数值。
  • for 循环:遍历每个类别型特征列,使用 LabelEncoderfit_transform 方法将该列的文本数据转换为整数编码,并更新 data 中的对应列。
    • fit_transform(data[col])fit_transformLabelEncoder 类的一个方法,它实际上是 fittransform 两个操作的组合。
      • fit 操作:会学习 data[col] 列中所有不同的类别值,并为每个类别分配一个唯一的整数编码。例如,如果 data['color'] 列中有 'red''blue''green' 这三个不同的类别,fit 操作会为它们分别分配一个整数,比如 'red' 为 0,'blue' 为 1,'green' 为 2。
      • transform 操作:会根据 fit 操作学习到的编码规则,将 data[col] 列中的每个类别值替换为对应的整数编码。
    • data[col] = ...:将转换后的整数编码结果重新赋值给 data 数据集中的对应列,从而完成了该列类别型数据的数值转换。

举例说明:
假设 data 数据集中的 color 列有以下数据:

color
red
blue
red
green

经过 LabelEncoder 编码后,可能会变成:

color
0
1
0
2

通过这种方式,原本的文本类别型数据就被转换为了数值型数据,便于后续机器学习模型的处理。

5. 分离目标变量和特征

# 目标变量和特征
X = data.drop(columns=['price'])  # 除去price参数外其余的所有参数为特征
y = data['price']
  • X:特征矩阵,通过删除 data 中的 price 列得到。
  • y:目标变量,即 data 中的 price 列。

6. 定义待测试的超参数

# 待测试的超参数
params = [
    {'criterion': 'squared_error', 'max_depth': 12},
    {'criterion': 'friedman_mse', 'max_depth': 16},
    {'criterion': 'poisson', 'max_depth': 22},
    {'criterion': 'squared_error', 'max_depth': 45},
    {'criterion': 'friedman_mse', 'max_depth': 95},
    {'criterion': 'poisson', 'max_depth': 33},
]

params 是一个列表,其中每个元素是一个字典,包含了决策树回归模型的超参数组合,包括 criterion(分裂准则)和 max_depth(树的最大深度)。

7. 模型评估

# 模型评估
best_score = -float('inf')
best_params = None

for param in params:
    model = DecisionTreeRegressor(criterion=param['criterion'], max_depth=param['max_depth'], random_state=42)
    scores = cross_val_score(model, X, y, cv=10, scoring='r2')
    mean_score = scores.mean()
    print(f"参数: {param}, 平均R^2: {mean_score}")
    if mean_score > best_score:
        best_score = mean_score
        best_params = param

print("最佳参数:", best_params)
print("最佳R^2:", best_score)
  • best_score:初始化最佳得分,设为负无穷大。
  • best_params:初始化最佳超参数组合,设为 None
  • for 循环:遍历每个超参数组合,对于每个组合:
    • 创建一个 DecisionTreeRegressor 模型,使用当前超参数组合进行初始化。
    • 使用 cross_val_score 函数进行 10 折交叉验证,计算模型在不同子集上的 R 2 R^2 R2 得分。
    • 计算平均 R 2 R^2 R2 得分。
    • 打印当前超参数组合和平均 R 2 R^2 R2 得分。
    • 如果当前平均得分大于最佳得分,则更新最佳得分和最佳超参数组合。
  • 最后打印出最佳超参数组合和对应的最佳 R 2 R^2 R2 得分。

代码

import pandas as pd
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeRegressor
from sklearn.utils import shuffle
from sklearn.preprocessing import LabelEncoder

# 加载数据
data = pd.read_csv('/content/TRAIN.csv')


# 数据预处理
data = data.drop(data.columns[0], axis=1) # 删除重复索引列(第一列为没用的索引列)
# data = data.drop(columns=['unnecessary_column'])  # 或使用方法指定删除不必要的列
data = shuffle(data, random_state=42)  # 打乱样本

# 转换类别型特征(这是文本需要转化成数字参数的部分)
categorical_features = ['cut', 'color', 'clarity']
label_encoders = {col: LabelEncoder() for col in categorical_features}
for col in categorical_features:
    data[col] = label_encoders[col].fit_transform(data[col])

# 目标变量和特征
X = data.drop(columns=['price'])  # 除去price参数外其余的所有参数为特征
y = data['price']

# 待测试的超参数
params = [
    {'criterion': 'squared_error', 'max_depth': 12},
    {'criterion': 'friedman_mse', 'max_depth': 16},
    {'criterion': 'poisson', 'max_depth': 22},
    {'criterion': 'squared_error', 'max_depth': 45},
    {'criterion': 'friedman_mse', 'max_depth': 95},
    {'criterion': 'poisson', 'max_depth': 33},
]

# 模型评估
best_score = -float('inf')
best_params = None

for param in params:
    model = DecisionTreeRegressor(criterion=param['criterion'], max_depth=param['max_depth'], random_state=42)
    scores = cross_val_score(model, X, y, cv=10, scoring='r2')
    mean_score = scores.mean()
    print(f"参数: {param}, 平均R^2: {mean_score}")
    if mean_score > best_score:
        best_score = mean_score
        best_params = param

print("最佳参数:", best_params)
print("最佳R^2:", best_score)

输出:
在这里插入图片描述