c

codeye

V1

2022/09/29阅读:16主题:默认主题

初学者的回归分析 - 第二部分

初学者的回归分析 - 第二部分

使用基于树的算法(决策树、随机森林、XGboost)建立一个ML回归模型

  • 简介
  • 第2.1部分 建立机器学习管道

∘ 第1步:收集数据

∘ 第二步:将数据可视化(问自己这些问题并回答)

∘ 第三步:清理数据

∘ 第四步:訓練模型

∘ 第五步:評估

∘ 第六步:使用hyperopt进行超参数调整

∘ 第七步:选择最佳模型和预测结果

  • 第2.2部分:分析ML算法

∘ 什么是决策树?

∘ 什么是随机森林?

∘ 什么是极限梯度提升法?(XGBoost)

∘ 决策树 vs 随机森林 vs XGBoost

∘ 线性模型与树状模型的对比。

  • 总结

引言

正如我在上一篇文章中所解释的,真正的数据科学家是从问题/应用的角度来思考的,并在编程语言或框架的帮助下找到解决问题的方法。在第一部分中,鱼的重量估计问题是用线性ML模型解决的,然而,今天我将介绍基于树的算法,如决策树,随机森林,XGBoost来解决同样的问题。在文章的前半部分2.1部分,我将建立一个模型,在后半部分2.2部分,我将从理论上解释每一种算法,将它们相互比较并找出其优点和缺点。

第2.1部分 构建机器学习管道

为了建立一个ML模型,我们需要遵循下面的管道步骤,几乎所有种类的模型都是如此。

图片由作者提供 由于我们要解决的问题和以前一样,一些管道步骤也是一样的,比如1.收集数据,2.可视化数据。然而,其他步骤会有一些修改。

步骤1:收集数据 数据是可以从Kaggle上下载的公共数据集。


import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from itertools import combinations
import numpy as np
data = pd.read_csv("Fish.csv")

第2步:可视化数据(问自己这些问题并回答)

数据看起来是什么样子的?

data.head()

数据是否有缺失值?

data.isna().sum()

数字特征的分布是怎样的?

data_num = data.drop(columns=["Species"])

fig, axes = plt.subplots(len(data_num.columns)/3, 3, figsize=(15, 6))
i = 0
for triaxis in axes:
    for axis in triaxis:
        data_num.hist( column = data_num.columns[i], ax=axis)
        i = i+1

目标变量(重量)相对于鱼种的分布是什么?

sns.deposot(
  data=data,
  x="重量"
  hue="Species",
  kind="hist",
  height=6,
  aspect=1.4,
  bins=15
)
plt.show()

目标变量在物种方面的分布表明,有一些物种,如梭鱼,与其他物种相比具有巨大的权重。这种可视化给我们提供了更多关于 "物种 "特征如何被用于预测的信息。

sns.pairplot(data, kind='scatter', hue='Species')
plt.figure(figsize=(7,6))
corr = data_num.corr()
sns.heatmap(corr, 
            xticklabels=corr.columns.values,
            yticklabels=corr.columns.values, annot=True)
plt.show()

第3步:清理数据


from sklearn.model_selection import train_test_split
from sklearn.preprocessing import  LabelEncoder
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
import xgboost as xgb
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
data_cleaned =   data.drop("Weight", axis=1)
y = data['Weight']
x_train, x_test, y_train, y_test = train_test_split(data_cleaned,y, test_size=0.2, random_state=42)
print(x_train.shape, x_test.shape, y_train.shape, y_test.shape)
# label encoder
label_encoder = LabelEncoder()
x_train['Species'] = label_encoder.fit_transform(x_train['Species'].values)
x_test['Species'] = label_encoder.transform(x_test['Species'].values)

标签编码器

label_encoder = LabelEncoder()
x_train['Species'] = label_encoder.fit_transform(x_train['Species'].value)
x_test['Species'] = label_encoder.transform(x_test['Species'].values)

我们使用的是基于树的模型,因此我们不需要特征缩放。此外,为了将文本转换成数字,我只是用LabelEncoder给每个鱼种分配了唯一的数值。

第四步:训练模型


def evauation_model(pred, y_val):
  score_MSE = round(mean_squared_error(pred, y_val),2)
  score_MAE = round(mean_absolute_error(pred, y_val),2)
  score_r2score = round(r2_score(pred, y_val),2)
  return score_MSE, score_MAE, score_r2score


def models_score(model_name, train_data, y_train, val_data,y_val):
    model_list = ["Decision_Tree","Random_Forest","XGboost_Regressor"]
    #model_1
    if model_name=="Decision_Tree":
        reg = DecisionTreeRegressor(random_state=42)
    #model_2
    elif model_name=="Random_Forest":
      reg = RandomForestRegressor(random_state=42)
        
    #model_3
    elif model_name=="XGboost_Regressor":
        reg = xgb.XGBRegressor(objective="reg:squarederror",random_state=42,)
    else:
        print("please enter correct regressor name")
        
    if model_name in model_list:
        reg.fit(train_data,y_train)
        pred = reg.predict(val_data)
     
        score_MSE, score_MAE, score_r2score = evauation_model(pred,y_val)
        return round(score_MSE,2), round(score_MAE,2), round(score_r2score,2)
model_list = ["Decision_Tree","Random_Forest","XGboost_Regressor"]
result_scores = []
for model in model_list:
    score = models_score(model, x_train, y_train, x_test, y_test)
    result_scores.append((model, score[0], score[1],score[2]))
    print(model,score)

我训练了决策树、随机森林XGboost并存储了所有的评估分数。

第5步:评估

df_result_scores = pd.DataFrame(result_scores,columns ["model""mse""mae""r2score"])
df_result_scores

基于树的算法的评估结果 基于树的模型 这个结果真的很吸引人,你记得线性模型取得的结果要低得多(也如下图所示)。因此,在我们做任何类型的超参数调整之前,我们可以说所有基于树的模型在这种数据集中的表现都超过了线性模型。

线性模型的评估结果

线性模型

第6步:使用hyperopt进行超参数调整 今天我们使用hyperopt来调整使用TPE算法的超参数。TPE算法不是从搜索空间中随机取值,而是考虑到一些超参数的分配(x)是已知的,在其他元素的特定值下是不相关的。在这种情况下,搜索比随机搜索有效,比贪婪搜索快。


from hyperopt import hp
from hyperopt import fmin, tpe, STATUS_OK, STATUS_FAIL, Trials
from sklearn.model_selection import cross_val_score
num_estimator = [100,150,200,250] 。

space= {'max_depth': hp.quniform("max_depth", 3, 18, 1),
        'gamma': hp.uniform ('gamma', 1,9),
        'reg_alpha' : hp.quniform('reg_alpha', 30,180,1),
        'reg_lambda' : hp.uniform('reg_lambda', 0,1),
        'colsample_bytree' : hp.uniform('colsample_bytree', 0.5,1),
        'min_child_weight' : hp.quniform('min_child_weight', 0, 10, 1),
        'n_estimators' : hp.choice("n_estimators", num_estimator),
    }

def hyperparameter_tuning(space):
    model=xgb.XGBRegressor(n_estimators = space['n_estimators'], max_depth = int(space['max_depth']), gamma = space['gamma'],
                         reg_alpha = int(space['reg_alpha']) , min_child_weight=space['min_child_weight']。
                         colsample_bytree=space['colsample_bytree'], objective="reg:squarederror")
    
    score_cv = cross_val_score(model, x_train, y_train, cv=5, scoring="neg_mean_absolute_error") 。
    返回 {'损失':-score_cv, '状态': STATUS_OK, 'model': model}


trials = Trials()
best = fmin(fn=hyperparameter_tuning,
            space=空间。
            algo=tpe.commend,
            max_evals=200。
            trials=trials)

print(best)

找到的超参数 hyperopt 最佳超参数的结果 这里是算法在200次试验后发现的最佳超参数的结果。但是,如果数据集太大,可以相应减少试验次数。

best['max_depth'] = int(best['max_depth']) 
# 转换为int

best["n_estimators"] = num_estimator[best["n_estimators"]]
#

根据索引计算出的数值

reg = xgb.XGBRegressor(**best)
reg.fit(x_train,y_train)
pred = reg.predict(x_test)
score_MSE, score_MAE, score_r2score = evauation_model(pred,y_test) 
to_append = ["XGboost_hyper_tuned",score_MSE, score_MAE, score_r2score]
df_result_scores.loc[len(df_result_scores)] = to_append
df_result_scores

结果非常好! 与其他算法相比,这个超调模型真的很好。例如,XGboost将MAE的结果从41.65提高到36.33。

这是一个很好的例子,说明了超参数调整是多么强大。

第7步:选择最佳模型和预测

赢家

reg = xgb.XGBRegressor(**best)
reg.fit(x_train,y_train)
pred = reg.predict(x_test)
plt.figure(figsize=(18,7))
plt.subplot(1, 2, 1) # 第1行,第2列索引1
plt.scatter(range(0,len(x_test)), pred,color="green", label="predicted")
plt.scatter(range(0,len(x_test)), y_test,color="red",label="True value")
plt.legend()
plt.subplot(1, 2, 2) # 索引2
plt.plot(range(0,len(x_test)), pred,color="green",label=" predicted")
plt.plot(range(0,len(x_test)), y_test,color="red",label="true value")
plt.legend()
plt.show()

预测与真实 这个可视化图清楚地说明了预测值和真值有多接近,以及调整后的XGBoost的表现有多好。

第2.2部分 分析ML算法 什么是决策树? 决策树是一种有监督的ML算法,善于捕捉特征和目标变量之间的非线性关系。算法背后的直觉类似于人类的逻辑。在每个节点中,该算法找到特征和阈值,在此基础上将数据分成两部分。下面是决策树的图示。

鱼类重量预测决策树

首先,让我们看看图中每个变量代表什么。让我们以第一个节点为例。


width≤5.154:
特征和数值的阈值,算法根据这个阈值决定分割数据样本。

samples = 127: 
分割前有127个数据点。

value = 386.794
#预测特征(鱼的重量)的平均值。

Squared_error = 122928.22: 与MSE(true, pred)相同 - 其中pred与value(样本的平均鱼重)相同。

因此,基于宽度≤5.154的阈值的算法将数据分成两部分。但问题是该算法是如何找到这个阈值的?有几种分割标准,对于回归任务来说,CART算法试图通过贪婪的搜索方式找到一个阈值,使两个子组的加权平均MSE最小。

例如,在我们的案例中,在第一次拆分后,与其他拆分相比,两个子组的加权平均MSE是最小的。


J(k,t_k) = 88/127 *20583.394 + 39/127 *75630.727 = 37487.69

决策树的问题。

树对训练数据的微小变化非常敏感。数据的微小变化会导致决策树的结构发生重大变化。解决这一限制的方法是随机森林。

什么是随机森林?

随机森林是一个决策树的集合体。随机森林背后的直觉是建立多个决策树,在每个决策树中,它不是寻找分割数据的最佳特征,而是在一个特征子集中寻找最佳特征,因此这提高了树的多样性。然而,它的可解释性比简单的决策树要差。另外,它需要大量的树来构建,这使得该算法对于实时应用来说很慢。一般来说,算法的训练速度快,但创建预测的速度慢。决策树的一个改进版本也是XGBoost。

什么是极限梯度提升法?(XGBoost)

XGBoost也是一种基于树的集合监督学习算法,它使用梯度提升框架。这种算法背后的直觉是,它试图将新的预测器与前一个预测器的残余误差相适应。它的速度极快,可扩展,可移植。

决策树 vs 随机森林 vs XGBoost

因此,在我们的实验中,XGboost在性能上优于其他。从理论上讲,我们可以得出结论,决策树是最简单的基于树的算法,它有不稳定的局限性--数据的变化会导致树结构的巨大变化,然而,它有完美的可解释性。随机森林和XGboost则更为复杂。其中一个区别是,随机森林在过程结束时结合了结果(多数规则),而XGboost则在过程中结合了结果。一般来说,XGboost比随机森林有更好的性能,然而,当我们的数据中有大量的噪音时,XGBoost不能成为一个好的选择,它会导致过拟合,而且比随机森林更难调整。

线性模型与基于树的模型。

线性模型捕捉自变量和因变量之间的线性关系,这在现实世界场景的大多数情况下并不是这样的。然而,基于树的模型捕获了更复杂的关系。

线性模型大多数时候都需要进行特征缩放,但是基于树的模型不需要。 基于树的模型的性能多数时候比线性模型好。我们的实验很好地说明了这一点,最好的超调线性模型取得了66.20的MAE,而最好的树状模型取得了36.33,这是一个很大的进步。

基于树的算法比线性模型更容易解释。

结论 如前所述,对于哪种类型的算法效果最好,没有现成的收据,一切都取决于数据和任务。这就是为什么应该对几种算法进行测试和评估。然而,了解每一种算法背后的直觉,它们的优点和缺点是什么,以及如何应对其局限性是有好处的。

这里是我GitHub中的完整代码。

数据科学家并不是懂得python、Sklearn、TensorFlow等的人。但是,谁是谁,谁知道如何玩弄这些东西。 媒介.com

参考文献 [1] Stephanie Glen Decision Tree vs Random Forest vs Gradient Boosting Machines: 简单解释一下(2018)

[2] Vishal Morde XGBoost算法。愿她长久统治! (2019)

[3] GAURAV SHARMA,你应该知道的5种回归算法--介绍性指南!

[4] Aarshay Jain,《XGBoost中的参数调整完整指南》,用Python编写的代码

[5] scikit-learn.org,决策树,了解决策树结构¶。

[6] Hyperopt: 分布式异步超参数优化

[7] XGboost, XGBoost参数

[8] TINU ROHITH D, HyperParameter Tuning - Hyperopt Bayesian Optimization for (Xgboost and Neural network) (2019)

[9] Jobs Admin,你需要知道的另一种超参数优化技术--Hyperopt (2020)

[10] Aurelien Geron,用Scikit-learn和Tensorflow进行机器学习的实践(2019)

分类:

后端

标签:

后端

作者介绍

c
codeye
V1