Python 机器学习算法交易实用指南(三)(5)

简介: Python 机器学习算法交易实用指南(三)

Python 机器学习算法交易实用指南(三)(4)https://developer.aliyun.com/article/1523357

二阶损失函数近似

最重要的算法创新通过使用依赖于二阶导数的近似来降低评估损失函数的成本,类似于牛顿法找到稳定点。因此,在贪婪树扩展过程中评分潜在分割的速度相对于使用完整损失函数更快。

正如先前提到的,梯度提升模型是以增量方式训练的,其目标是最小化整体 H[M] 的预测误差和正则化惩罚的组合。用 m 步后集成对结果 y[i] 的预测表示为 ŷ[i]^((m)),l 是一个可微的凸损失函数,用来衡量结果和预测之间的差异,Ω 是一个随着整体 H[M] 复杂性增加而增加的惩罚项,增量假设 h[m] 的目标是最小化以下目标函数:


正则化惩罚有助于通过偏好选择使用简单且有预测性的回归树的模型来避免过拟合。例如,在 XGBoost 的情况下,回归树 h 的惩罚取决于每棵树的叶子数 T,每个终端节点的回归树得分 w,以及超参数 γ 和 λ。这在以下公式中总结如下:


因此,在每一步,算法都会贪婪地添加最能改进正则化目标的假设 h[m]。基于泰勒展开的损失函数的二阶近似加速了目标函数的评估,如以下公式所总结:


这里,g[i] 是添加新的学习器前给定特征值的损失函数的一阶梯度,而 h[i] 是相应的二阶梯度(或者海森矩阵)值,如下式所示:


XGBoost 算法是第一个利用损失函数的这种近似来计算给定树结构的最优叶子分数和相应损失函数值的开源算法。分数由终端节点中样本的梯度和 Hessian 的和的比率组成。它使用此值来评分分裂所导致的信息增益,类似于我们在前一章中看到的节点不纯度度量,但适用于任意损失函数(详细推导请参阅 GitHub 上的参考文献)。

简化的分裂查找算法

sklearn 的梯度提升实现找到枚举连续特征所有选项的最优拆分。这种精确的贪婪算法在计算上非常耗费资源,因为它必须首先按特征值对数据进行排序,然后对潜在的非常大数量的拆分选项进行评分和决策。当数据不适合内存或在多台机器上的分布式设置中进行训练时,此方法会面临挑战。

一种近似的分裂查找算法通过将特征值分配给用户确定的一组箱子来减少分裂点的数量,这也可以在训练期间大大减少内存需求,因为每个箱子只需要存储一个分裂。XGBoost 引入了一种分位数草图算法,也能将加权训练样本分成百分位箱子,以实现均匀分布。XGBoost 还引入了处理稀疏数据的能力,这些数据由缺失值、频繁的零梯度统计和一位有效编码引起,并且还可以为给定的分裂学习一个最优的默认方向。因此,该算法只需评估非缺失值。

相比之下,LightGBM 使用基于梯度的单侧采样GOSS)来排除具有小梯度的大部分样本,并且仅使用其余部分来估算信息增益,并相应地选择分裂值。具有较大梯度的样本需要更多的训练,并且倾向于更多地对信息增益做出贡献。LightGBM 还使用排他性特征绑定来组合那些彼此互斥的特征,它们很少同时取非零值,以减少特征数量。因此,LightGBM 在发布时是最快的实现。

深度优先与叶子优先增长

LightGBM 与 XGBoost 和 CatBoost 在优先拆分哪些节点方面有所不同。LightGBM 以叶子方式决定分裂,即拆分最大化信息增益的叶子节点,即使这会导致不平衡树。相比之下,XGBoost 和 CatBoost 以深度方式扩展所有节点,并在添加更多级别之前首先拆分给定深度的所有节点。这两种方法以不同的顺序扩展节点,除了完整的树之外,它们将产生不同的结果。下图说明了这两种方法:


LightGBM 的叶子优先分割往往增加模型复杂性,并且可能加快收敛速度,但也增加了过拟合的风险。一个深度为 n 的以节点为优先的树最多有 2^(n )个叶子节点,而一个以叶子为优先的树具有 2^n 个叶子,可能会有更多的层次,并且某些叶子节点中包含相对较少的样本。因此,调整 LightGBM 的 num_leaves 设置需要额外的注意,库也允许我们同时控制 max_depth 以避免不必要的节点不平衡。LightGBM 的更近期版本还提供了深度为优先的树增长。

基于 GPU 的训练

所有新的实现支持在一个或多个 GPU 上进行训练和预测,以实现显著的加速。它们与当前的 CUDA 启用的 GPU 兼容。安装要求各不相同,并且正在快速发展。XGBoost 和 CatBoost 的实现适用于几个当前版本,但是 LightGBM 可能需要本地编译(请参阅 GitHub 获取相关文档链接)。

加速取决于库和数据类型,并且范围从低的单位数字倍增到数十倍的因子。仅需更改任务参数并且不需要其他超参数修改就能激活 GPU。

DART – 树的 dropout

2015 年,Rashmi 和 Gilad-Bachrach 提出了一个新模型来训练梯度提升树,旨在解决他们称之为过度专业化的问题:在后续迭代中添加的树往往只影响少数实例的预测,而对于其余实例的贡献较小。然而,该模型的样本外性能可能会受到影响,并且可能对先前在过程中添加的少数树的贡献过于敏感。

新的算法采用了 dropouts,成功地用于学习更准确的深度神经网络,其中 dropouts 在学习过程中静音了部分神经连接。因此,高层节点不能依赖少数连接来传递预测所需的信息。这种方法对于深度神经网络的成功做出了重要贡献,也已与其他学习技术一起使用,例如逻辑回归,以静音特征的随机份额。随机森林和随机梯度提升也会静音随机特征子集。

DART 在树的层次上运作,并且对整棵树进行静音,而不是对个别特征进行操作。使用 DART 生成的集成树的目标是更均匀地对最终预测作出贡献。在某些情况下,这已被证明对排名、回归和分类任务产生更准确的预测。该方法首先在 LightGBM 中实现,并且也适用于 XGBoost。

分类特征的处理

CatBoost 和 LightGBM 实现直接处理分类变量,无需虚拟编码。

CatBoost 的实现(其命名源自对分类特征的处理)包括处理这些特征的几个选项,除了自动独热编码外,还为几个特征的单独分类或多个特征组合分配数字值。换句话说,CatBoost 可以从现有特征的组合中创建新的分类特征。与个别特征或特征组合的分类水平相关的数字值取决于它们与结果值的关系。在分类情况下,这与观察正类别的概率有关,该概率在样本上累积计算,基于先验和平滑系数。有关更详细的数值示例,请参阅文档。

LightGBM 的实现将分类特征的水平分组以最大化(或最小化)与结果值相对于组内的均匀性。

XGBoost 的实现不直接处理分类特征,需要进行独热(或虚拟)编码。

其他功能和优化

XGBoost 通过在内存中保留压缩的列块来优化计算,在几个方面使计算多线程化,其中每个列都按相应特征值排序。XGBoost 在训练前仅计算一次此输入数据布局,并在整个过程中重复使用它以摊销额外的前期成本。使用可以并行完成的分位数时,对列的拆分统计信息的搜索变为线性扫描,并且易于支持列子抽样。

后来发布的 LightGBM 和 CatBoost 库构建在这些创新之上,并通过优化线程和减少内存使用量进一步加速了训练。由于它们的开源性质,这些库随着时间的推移往往会趋于一致。

XGBoost 还支持单调性约束。这些约束确保给定特征的值仅在其整个范围内与结果呈正相关或负相关。它们对于合并已知为真的模型的外部假设非常有用。

如何使用 XGBoost、LightGBM 和 CatBoost

XGBoost、LightGBM 和 CatBoost 提供多种语言的接口,包括 Python,并且具有与其他 sklearn 特性兼容的 sklearn 接口,例如 GridSearchCV,以及它们自己的方法来训练和预测梯度提升模型。gbm_baseline.ipynb 笔记本展示了每个实现的 sklearn 接口的使用。这些库方法通常文档更好,而且也更容易使用,因此我们将使用它们来说明这些模型的使用。

该过程涉及创建特定于库的数据格式,调整各种超参数以及评估我们将在接下来的章节中描述的结果。 附带的笔记本包含gbm_tuning.pygbm_utils.pygbm_params.py文件,共同提供以下功能,并生成相应的结果。

如何创建二进制数据格式

所有库都有自己的数据格式,用于预先计算特征统计信息以加速搜索分割点,如前所述。 这些也可以持久化以加速后续训练的开始。

以下代码为要与OneStepTimeSeriesSplit一起使用的每个模型构造了二进制训练和验证数据集:

cat_cols = ['year', 'month', 'age', 'msize', 'sector']
data = {}
for fold, (train_idx, test_idx) in enumerate(kfold.split(features)):
    print(fold, end=' ', flush=True)
    if model == 'xgboost':
        data[fold] = {'train': xgb.DMatrix(label=target.iloc[train_idx],
                                           data=features.iloc[train_idx],
                                           nthread=-1),                  # use avail. threads
                      'valid': xgb.DMatrix(label=target.iloc[test_idx],
                                           data=features.iloc[test_idx],
                                           nthread=-1)}
    elif model == 'lightgbm':
        train = lgb.Dataset(label=target.iloc[train_idx],
                            data=features.iloc[train_idx],
                            categorical_feature=cat_cols,
                            free_raw_data=False)
        # align validation set histograms with training set
        valid = train.create_valid(label=target.iloc[test_idx],
                                   data=features.iloc[test_idx])
        data[fold] = {'train': train.construct(),
                      'valid': valid.construct()}
    elif model == 'catboost':
        # get categorical feature indices
        cat_cols_idx = [features.columns.get_loc(c) for c in cat_cols]
        data[fold] = {'train': Pool(label=target.iloc[train_idx],
                                    data=features.iloc[train_idx],
                                    cat_features=cat_cols_idx),
                      'valid': Pool(label=target.iloc[test_idx],
                                    data=features.iloc[test_idx],
                                    cat_features=cat_cols_idx)}

可用选项略有不同:

  • xgboost 允许使用所有可用线程
  • lightgbm明确地将为验证集创建的分位数与训练集对齐
  • catboost 实现需要使用索引而不是标签来识别特征列

如何调整超参数

许多超参数在gbm_params.py中列出。 每个库都有参数设置来:

  • 指定总体目标和学习算法
  • 设计基学习器
  • 应用各种正则化技术
  • 在训练过程中处理提前停止
  • 启用 GPU 或在 CPU 上进行并行化

每个库的文档详细介绍了可能引用相同概念的各种参数,但是在库之间具有不同名称的参数。 GitHub 存储库包含指向突出显示xgboostlightgbm相应参数的网站的链接。

目标和损失函数

这些库支持几种提升算法,包括树的梯度提升和线性基学习器,以及 LightGBM 和 XGBoost 的 DART。 LightGBM 还支持我们之前描述的 GOSS 算法,以及随机森林。

梯度提升的吸引力在于有效支持任意可微损失函数,每个库都提供了用于回归,分类和排名任务的各种选项。 除了选择的损失函数之外,在训练和交叉验证期间还可以使用其他评估指标来监视性能。

学习参数

梯度提升模型通常使用决策树来捕获特征交互,个体树的大小是最重要的调整参数。 XGBoost 和 CatBoost 将max_depth默认设置为 6。 相反,LightGBM 使用默认的num_leaves值为 31,这对应于平衡树的五个级别,但对级别的数量没有约束。 为了避免过拟合,num_leaves应低于2^(max_depth)。 例如,对于表现良好的max_depth值为 7,您应将num_leaves设置为 70–80,而不是 2⁷=128,或者直接限制max_depth

树的数量或增强迭代次数定义了整体集合的规模。所有库都支持early_stopping,一旦损失函数在给定迭代次数内不再改善,就会终止训练。因此,通常最好设置大量迭代次数,并根据验证集上的预测性能停止训练。

正则化

所有库都实现了对基本学习器的正则化策略,例如样本数量的最小值或分割和叶节点所需的最小信息增益。

它们还支持通过学习速率通过收缩来在整个集合层次上实现正则化,限制新树的贡献。还可以通过回调函数实现自适应学习速率,随着训练的进行而降低学习速率,这在神经网络的上下文中已经成功使用过。此外,梯度提升损失函数可以通过* L1 L2 进行正则化,类似于通过修改Ω( h [m] *)或通过增加添加更多树的惩罚γ来描述的 Ridge 和 Lasso 线性回归模型。

这些库还允许使用装袋或列子抽样来随机化树的生长,用于随机森林,并减少整体方差以去相关预测误差。为了保护免受过拟合,对于近似分割查找的特征量化,添加更大的箱子作为另一种选择。

随机化网格搜索

为了探索超参数空间,我们为我们想要测试的关键参数指定值。sklearn 库支持RandomizedSearchCV,从指定的分布中随机抽样一部分参数组合进行交叉验证。我们将实现一个自定义版本,允许我们利用早停,同时监视当前表现最佳的组合,因此我们可以在满意结果时中止搜索过程,而不是事先指定一组迭代次数。

为此,我们根据每个库的参数指定参数网格,使用itertools库提供的内置笛卡尔product生成器生成所有组合,并随机shuffle结果。在 LightGBM 的情况下,我们会自动根据当前num_leaves值设置max_depth,如下所示:

param_grid = dict(
        # common options
        learning_rate=[.01, .1, .3],
        colsample_bytree=[.8, 1],  # except catboost
        # lightgbm
        num_leaves=[2 ** i for i in range(9, 14)],
        boosting=['gbdt', 'dart'],
        min_gain_to_split=[0, 1, 5],  # not supported on GPU
all_params = list(product(*param_grid.values()))
n_models = len(all_params) # max number of models to cross-validate
shuffle(all_params)

然后,我们执行交叉验证如下:

GBM = 'lightgbm'
for test_param in all_params:
    cv_params = get_params(GBM)
    cv_params.update(dict(zip(param_grid.keys(), test_param)))
    if GBM == 'lightgbm':
        cv_params['max_depth'] = int(ceil(np.log2(cv_params['num_leaves'])))
    results[n] = run_cv(test_params=cv_params,
                        data=datasets,
                        n_splits=n_splits,
                        gb_machine=GBM)

run_cv函数实现了三个库的交叉验证。对于light_gbm示例,该过程如下:

def run_cv(test_params, data, n_splits=10):
    """Train-Validate with early stopping"""
    result = []
    cols = ['rounds', 'train', 'valid']
    for fold in range(n_splits):
        train = data[fold]['train']
        valid = data[fold]['valid']
        scores = {}
        model = lgb.train(params=test_params,
                          train_set=train,
                          valid_sets=[train, valid],
                          valid_names=['train', 'valid'],
                          num_boost_round=250,
                          early_stopping_rounds=25,
                          verbose_eval=50,
                          evals_result=scores)
        result.append([model.current_iteration(),
                       scores['train']['auc'][-1],
                       scores['valid']['auc'][-1]])
    return pd.DataFrame(result, columns=cols)

train()方法还会生成存储在scores字典中的验证分数。当早停生效时,最后一次迭代也是最佳分数。有关更多详细信息,请参见 GitHub 上的完整实现。

如何评估结果

使用 GPU,我们可以在几分钟内训练一个模型,并在几个小时内评估数百个参数组合,而使用 sklearn 实现则需要多天。对于 LightGBM 模型,我们探索了使用库处理分类变量的因子版本和使用独热编码的虚拟版本。

结果存储在 model_tuning.h5 HDF5 存储中。模型评估代码样本在 eval_results.ipynb 笔记本中。

跨模型的交叉验证结果

当比较四次测试运行中三个库的平均交叉验证 AUC 时,我们发现 CatBoost 为表现最佳模型产生了稍高的 AUC 分数,同时也产生了最广泛的结果分布,如下图所示:


表现最佳的 CatBoost 模型使用以下参数(详见笔记本):

  • max_depth 为 12,max_bin 为 128
  • max_ctr_complexity 为 2,限制了分类特征的组合数量
  • one_hot_max_size 为 2,排除了二元特征的数值变量分配
  • random_strength 不等于 0 以随机化分裂的评估

训练相对于 LightGBM 和 XGBoost 稍慢(都使用 GPU),平均每个模型 230 秒。

对 LightGBM 和 XGBoost 模型表现最好的更详细的分析显示,LightGBM 因子模型的性能几乎与其他两个模型相当,但模型复杂度要低得多。它平均只包含 41 棵树,深度为三级,每棵树最多有八个叶子节点,并且还使用了 min_gain_to_split 形式的正则化。它在训练集上过拟合明显较少,训练 AUC 仅略高于验证 AUC。它还训练速度更快,每个模型只需 18 秒,因为它的复杂度更低。实际上,这个模型更可取,因为它更有可能产生良好的样本外表现。具体细节如下表所示:

LightGBM 虚拟 XGBoost 虚拟 LightGBM 因子
验证 AUC 68.57% 68.36% 68.32%
训练 AUC 82.35% 79.81% 72.12%
learning_rate 0.1 0.1 0.3
max_depth 13 9 3
num_leaves 8192 8
colsample_bytree 0.8 1 1
min_gain_to_split 0 1 0
轮数 44.42 59.17 41.00
时间 86.55 85.37 18.78

下图显示了不同 max_depth 设置对 LightGBM 和 XGBoost 模型的验证分数的影响:较浅的树产生了更广泛的结果范围,需要与适当的学习率和正则化设置相结合,以产生前面表格中显示的强结果:


与之前显示的 DecisionTreeRegressor 不同,我们也可以使用线性回归来评估不同特征在验证 AUC 分数方面的统计显著性。对于 LightGBM 虚拟模型,其中回归解释了结果变异的 68%,我们发现只有 min_gain_to_split 正则化参数不显著,如下图所示:


在实践中,深入了解模型如何进行预测非常重要,特别是对于投资策略,决策者通常需要合理的解释。

如何解释 GBM 结果

理解模型为什么预测某个结果对于多种原因都非常重要,包括信任、可操作性、责任和调试。通过模型发现的特征与结果之间的非线性关系以及特征之间的相互作用也在学习更多关于所研究现象的基本驱动因素时具有价值。

了解树集成方法(如梯度提升或随机森林模型)所做预测的见解的常见方法是将特征重要性值归因于每个输入变量。这些特征重要性值可以根据单个预测的情况或整个数据集(即所有样本)全局计算,以获得模型进行预测的更高级别视角。

特征重要性

有三种主要方法来计算全局特征重要性值:

  • Gain: 这种经典方法由 Leo Breiman 在 1984 年引入,使用给定特征的所有分割所贡献的损失或杂质的总减少。其动机在很大程度上是启发式的,但它是一种常用的特征选择方法。
  • 分割计数:这是一种替代方法,它计算使用特征进行分割决策的频率,根据选择特征以达到所得信息增益。
  • 排列:这种方法随机排列测试集中的特征值,并测量模型误差的变化量,假设重要特征应该会导致预测误差大幅增加。不同的排列选择导致该基本方法的替代实现。

对于单个预测计算特征重要性值的方法较少,因为可用的模型无关解释方法比树特定方法慢得多。

所有梯度提升实现在训练后都提供特征重要性得分作为模型属性。XGBoost 库提供五个版本,如下列表所示:

  • total_gaingain 作为其每个分割的平均值
  • total_cover 作为使用特征时每个分割的样本数
  • weight 作为前面值的分割计数

可使用训练模型的.get_score()方法和相应的importance_type参数获取这些值。对于性能最佳的 XGBoost 模型,结果如下(total度量具有 0.8 的相关性,covertotal_cover也是如此):


虽然不同月份和年份的指标占主导地位,但最近 1 个月的回报是从total_gain的角度来看第二重要的特征,并且根据weight度量经常被使用,但由于它平均应用于相对较少的实例而产生较低的平均收益(有关实施细节,请参见笔记本)。

偏依赖图

除了个体特征对模型预测的总体贡献之外,偏依赖图还可视化目标变量与一组特征之间的关系。梯度提升树的非线性特性导致这种关系取决于所有其他特征的值。因此,我们将对这些特征进行边际化处理。通过这样做,我们可以将偏依赖性解释为期望的目标响应。

我们只能为单个特征或特征对可视化偏依赖性。后者会产生等高线图,显示不同特征值的组合如何产生不同的预测概率,如下所示:

fig, axes = plot_partial_dependence(gbrt=gb_clf,
                                    X=X_dummies_clean,
                                    features=['month_9', 'return_1m', 'return_3m', ('return_1m', 'return_3m')],
                                    feature_names=['month_9','return_1m', 'return_3m'],
                                    percentiles=(0.01, 0.99),
                                    n_jobs=-1,
                                    n_cols=2,
                                    grid_resolution=250)

经过一些额外的格式化(请参阅配套笔记本),我们得到了以下图表:


右下角的图显示了在消除[1%,99%]百分位数处的离群值后,给定滞后 1 个月和 3 个月收益值范围的情况下,下个月产生正回报的概率的依赖性。 month_9 变量是一个虚拟变量,因此呈阶梯函数样式的图。我们还可以将依赖性可视化为 3D,如下代码所示:

targets = ['return_1m', 'return_3m']
target_feature = [X_dummies_clean.columns.get_loc(t) for t in targets]
pdp, axes = partial_dependence(gb_clf,
                               target_feature,
                               X=X_dummies_clean,
                               grid_resolution=100)
XX, YY = np.meshgrid(axes[0], axes[1])
Z = pdp[0].reshape(list(map(np.size, axes))).T
fig = plt.figure(figsize=(14, 8))
ax = Axes3D(fig)
surf = ax.plot_surface(XX, YY, Z,
                       rstride=1,
                       cstride=1,
                       cmap=plt.cm.BuPu,
                       edgecolor='k')
ax.set_xlabel(' '.join(targets[0].split('_')).capitalize())
ax.set_ylabel(' '.join(targets[1].split('_')).capitalize())
ax.set_zlabel('Partial Dependence')
ax.view_init(elev=22, azim=30)

这产生了以下 1 个月回报方向对滞后 1 个月和 3 个月回报的偏依赖的 3D 图:


SHapley Additive exPlanations

在 2017 年 NIPS 会议上,来自华盛顿大学的 Scott Lundberg 和 Su-In Lee 提出了一种新的更准确的方法来解释树集成模型对输出的贡献,称为SHapley Additive exPlanations,或SHAP值。

这个新算法基于这样一个观察:树集成的特征归因方法,如我们之前看过的方法,是不一致的——即,使特征对输出的影响增加的模型变化可能会降低该特征的重要性值(请参阅 GitHub 上有关此的详细说明)。

SHAP 值统一了协作博弈理论和局部解释的思想,并且根据期望值显示其在理论上是最优、一致和局部准确的。最重要的是,Lundberg 和 Lee 开发了一种算法,成功将计算这些与模型无关的、可加的特征归因方法的复杂度从 O(TLD^M) 减少到 O(TLD²),其中 TM 分别是树和特征的数量,DL 是树的最大深度和叶子节点数。这一重要的创新使得对先前难以处理的具有数千棵树和特征的模型的预测能够在几秒钟内解释。一个开源实现于 2017 年底发布,并且兼容 XGBoost、LightGBM、CatBoost 和 sklearn 树模型。

Shapley 值源自博弈论,是一种为协作游戏中的每个玩家分配值的技术,反映了他们对团队成功的贡献。SHAP 值是对基于树的模型的博弈论概念的一种改编,并且为每个特征和每个样本计算。它们衡量了一个特征对给定观察结果的模型输出的贡献。因此,SHAP 值提供了不同的洞察力,说明了特征的影响如何在样本间变化,这在这些非线性模型中交互作用效应的作用中非常重要。

如何按特征总结 SHAP 值

要获得对多个样本的特征重要性的高级概述,有两种绘制 SHAP 值的方法:对所有样本进行简单平均,类似于先前计算的全局特征重要性度量(如下图左侧面板所示),或者绘制散点图来显示每个样本的每个特征的影响(如下图右侧面板所示)。使用兼容库的训练模型和匹配输入数据非常容易产生,如下面的代码所示:

# load JS visualization code to notebook
shap.initjs()
# explain the model's predictions using SHAP values
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_test)
shap.summary_plot(shap_values, X_test, show=False)

下图右侧的散点图按照所有样本的 SHAP 值对特征进行排序,然后显示了每个特征对模型输出的影响,其值由特征的值的函数表示,通过其颜色表示,红色表示高值,蓝色表示低值,相对于特征的范围:


如何使用力图解释预测

下面的力图显示了各种特征及其值对模型输出的累积影响,在这种情况下,模型输出为 0.6,比基准值 0.13(提供的数据集上的平均模型输出)高得多。突出显示为红色的特征增加了输出。十月份是最重要的特征,将输出从 0.338 增加到 0.537,而 2017 年则降低了输出。

因此,我们获得了模型如何到达特定预测的详细分解,如下图所示:


我们还可以同时计算大量数据点或预测的力图,并使用聚类可视化来深入了解数据集中某些影响模式的普遍程度。以下图表显示了前 1000 个观察结果的力图,旋转了 90 度,水平堆叠,并按照不同特征对给定观察结果的影响排序。该实现使用层次凝聚聚类对特征 SHAP 值上的数据点进行标识以识别这些模式,并以交互方式显示结果进行探索性分析(参见笔记本),如以下代码所示:

shap.force_plot(explainer.expected_value, shap_values[:1000,:], X_test.iloc[:1000])

这将产生以下输出:


如何分析特征交互

最后,SHAP 值使我们能够通过将这些相互作用与主要效应分离来获得对不同特征之间的相互作用效应的额外洞察。shap.dependence_plot 可以定义如下:

shap.dependence_plot("return_1m", shap_values, X_test, interaction_index=2, title='Interaction between 1- and 3-Month Returns')

它显示了 1 个月回报的不同值(x 轴)如何影响结果(y 轴上的 SHAP 值),并由 3 个月回报区分:


SHAP 值在每个单独预测的水平上提供了细粒度的特征归因,并通过(交互式)可视化实现了对复杂模型的更丰富检查。本节开头显示的 SHAP 摘要散点图提供了比全局特征重要性条形图更加差异化的见解。单个聚类预测的力图允许进行更详细的分析,而 SHAP 依赖图捕获了相互作用效应,并因此提供了比局部依赖图更准确和详细的结果。

SHAP 值的限制与任何当前特征重要性度量一样,涉及对高度相关的变量影响的归因,因为它们相似的影响可能以任意方式被分解。

摘要

在本章中,我们探讨了梯度提升算法,该算法用于以顺序方式构建集成,添加一个只使用非常少的特征的浅层决策树,以改善已经做出的预测。我们看到了梯度提升树如何可以非常灵活地应用于广泛的损失函数,并提供了许多机会来调整模型以适应给定的数据集和学习任务。

最近的实现大大简化了梯度提升的使用,通过加速训练过程并提供更一致和详细的特征重要性以及单个预测驱动因素的洞察。在下一章中,我们将转向贝叶斯方法来进行机器学习。

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
4天前
|
机器学习/深度学习 人工智能 算法
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
文本分类识别系统。本系统使用Python作为主要开发语言,首先收集了10种中文文本数据集("体育类", "财经类", "房产类", "家居类", "教育类", "科技类", "时尚类", "时政类", "游戏类", "娱乐类"),然后基于TensorFlow搭建CNN卷积神经网络算法模型。通过对数据集进行多轮迭代训练,最后得到一个识别精度较高的模型,并保存为本地的h5格式。然后使用Django开发Web网页端操作界面,实现用户上传一段文本识别其所属的类别。
18 1
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
|
1天前
|
大数据 UED 开发者
实战演练:利用Python的Trie树优化搜索算法,性能飙升不是梦!
在数据密集型应用中,高效搜索算法至关重要。Trie树(前缀树/字典树)通过优化字符串处理和搜索效率成为理想选择。本文通过Python实战演示Trie树构建与应用,显著提升搜索性能。Trie树利用公共前缀减少查询时间,支持快速插入、删除和搜索。以下为简单示例代码,展示如何构建及使用Trie树进行搜索与前缀匹配,适用于自动补全、拼写检查等场景,助力提升应用性能与用户体验。
11 2
|
7天前
|
机器学习/深度学习 算法 数据挖掘
Python数据分析革命:Scikit-learn库,让机器学习模型训练与评估变得简单高效!
在数据驱动时代,Python 以强大的生态系统成为数据科学的首选语言,而 Scikit-learn 则因简洁的 API 和广泛的支持脱颖而出。本文将指导你使用 Scikit-learn 进行机器学习模型的训练与评估。首先通过 `pip install scikit-learn` 安装库,然后利用内置数据集进行数据准备,选择合适的模型(如逻辑回归),并通过交叉验证评估其性能。最终,使用模型对新数据进行预测,简化整个流程。无论你是新手还是专家,Scikit-learn 都能助你一臂之力。
47 8
|
4天前
|
算法 Python
震惊!Python 算法设计背后,时间复杂度与空间复杂度的惊天秘密大起底!
在 Python 算法设计中,理解并巧妙运用时间复杂度和空间复杂度的知识,是实现高效、优雅代码的必经之路。通过不断地实践和优化,我们能够在这两个因素之间找到最佳的平衡点,创造出性能卓越的程序。
19 4
|
5天前
|
算法 搜索推荐 开发者
别再让复杂度拖你后腿!Python 算法设计与分析实战,教你如何精准评估与优化!
在 Python 编程中,算法的性能至关重要。本文将带您深入了解算法复杂度的概念,包括时间复杂度和空间复杂度。通过具体的例子,如冒泡排序算法 (`O(n^2)` 时间复杂度,`O(1)` 空间复杂度),我们将展示如何评估算法的性能。同时,我们还会介绍如何优化算法,例如使用 Python 的内置函数 `max` 来提高查找最大值的效率,或利用哈希表将查找时间从 `O(n)` 降至 `O(1)`。此外,还将介绍使用 `timeit` 模块等工具来评估算法性能的方法。通过不断实践,您将能更高效地优化 Python 程序。
20 4
|
3天前
|
算法 程序员 Python
程序员必看!Python复杂度分析全攻略,让你的算法设计既快又省内存!
在编程领域,Python以简洁的语法和强大的库支持成为众多程序员的首选语言。然而,性能优化仍是挑战。本文将带你深入了解Python算法的复杂度分析,从时间与空间复杂度入手,分享四大最佳实践:选择合适算法、优化实现、利用Python特性减少空间消耗及定期评估调整,助你写出高效且节省内存的代码,轻松应对各种编程挑战。
15 1
|
4天前
|
机器学习/深度学习 数据可视化 数据挖掘
数据可视化大不同!Python数据分析与机器学习中的Matplotlib、Seaborn应用新视角!
在数据科学与机器学习领域,数据可视化是理解数据和优化模型的关键。Python凭借其强大的可视化库Matplotlib和Seaborn成为首选语言。本文通过分析一份包含房屋面积、卧室数量等特征及售价的数据集,展示了如何使用Matplotlib绘制散点图,揭示房屋面积与售价的正相关关系;并利用Seaborn的pairplot探索多变量间的关系。在机器学习建模阶段,通过随机森林模型展示特征重要性的可视化,帮助优化模型。这两个库在数据分析与建模中展现出广泛的应用价值。
18 2
|
4天前
|
算法 计算机视觉 Python
Python并查集大揭秘:让你在算法界呼风唤雨,秒杀一切复杂场景!
在编程与算法的广袤天地中,总有一些工具如同神兵利器,能够助你一臂之力,在复杂的问题前游刃有余。今天,我们就来深入探讨这样一件神器——Python并查集(Union-Find),看看它是如何让你在算法界呼风唤雨,轻松应对各种复杂场景的。
16 2
|
4天前
|
机器学习/深度学习 人工智能 算法
【果蔬识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
【果蔬识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台。果蔬识别系统,本系统使用Python作为主要开发语言,通过收集了12种常见的水果和蔬菜('土豆', '圣女果', '大白菜', '大葱', '梨', '胡萝卜', '芒果', '苹果', '西红柿', '韭菜', '香蕉', '黄瓜'),然后基于TensorFlow库搭建CNN卷积神经网络算法模型,然后对数据集进行训练,最后得到一个识别精度较高的算法模型,然后将其保存为h5格式的本地文件方便后期调用。再使用Django框架搭建Web网页平台操作界面,实现用户上传一张果蔬图片识别其名称。
20 0
【果蔬识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
|
7天前
|
缓存 算法 数据处理
时间&空间复杂度,Python 算法的双重考验!如何优雅地平衡两者,打造极致性能?
在Python算法中,时间与空间复杂度的平衡至关重要。时间复杂度反映算法执行时间随输入规模的变化趋势,空间复杂度则关注额外存储空间的需求。优秀的算法需兼顾两者,如线性搜索时间复杂度为O(n),空间复杂度为O(1);二分查找在时间效率上显著提升至O(log n),空间复杂度保持为O(1);动态规划通过牺牲O(n)空间换取O(n)时间内的高效计算。实际应用中,需根据具体需求权衡,如实时数据处理重视时间效率,而嵌入式系统更关注空间节约。通过不断优化,我们能在Python中找到最佳平衡点,实现高性能程序。
26 3