Python使用“决策树”算法解决预测钻石成本的问题
任务
我们的任务是训练一个基于决策树的标准回归器,以解决根据一组特征预测钻石成本的问题,这些特征包括:克拉数、颜色、净度、几何尺寸等。
你可以从这里找到数据集
在做之前,我们要看下数据集是什么样子?
观察后我们发现必须对数据集进行如下预处理:
- 删除重复索引的不必要的列;
- 将所有数据转换为数字类型(如有必要)*;
- 使用 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_score
是sklearn
中用于进行交叉验证并计算模型得分的函数。DecisionTreeRegressor
是sklearn
中用于实现决策树回归模型的类。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
循环:遍历每个类别型特征列,使用LabelEncoder
的fit_transform
方法将该列的文本数据转换为整数编码,并更新data
中的对应列。fit_transform(data[col])
:fit_transform
是LabelEncoder
类的一个方法,它实际上是fit
和transform
两个操作的组合。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)
输出: