在 PySpark ML 中LightGBM比XGBoost更好(二)

发布于:2025-09-11 ⋅ 阅读:(20) ⋅ 点赞:(0)

本篇文章Why XGBoost Isn’t Always the Answer for Forecasting — and How LightGBM in PySpark Can Do Better适合希望提升预测模型效率的数据科学家。文章的技术亮点在于LightGBM在PySpark中的应用,能够直接处理分类特征,减少特征工程的复杂性,且训练速度比XGBoost快30%。适用场景包括大规模数据集的财务预测,如逾期付款分析。实际案例展示了使用LightGBM后,模型训练时间从6小时降至2小时,现金流预测准确度提高了15%,显著提升了团队效率。



每秒钟,企业都会生成海量的财务和运营数据——发票、交易、传感器读数、日志。对于数据专业人士而言,挑战不仅在于分析这些数据,更在于预测未来:哪些客户会逾期付款?下个季度会有多少现金流可用?

大多数数据科学家会本能地选择 XGBoost。这有充分的理由:它是许多 Kaggle 获胜方案的基石,并已成为“可靠的 Boosting 算法”的代名词。

但这里有一个“肮脏的秘密”:XGBoost 并非总是适用于像 PySpark 这样的大规模分布式环境。你可能已经感受到了——繁琐的特征工程步骤、臃肿的流水线以及漫长的训练时间。

大多数人错误地认为:LightGBM 只是“另一种梯度 Boosting 库”。实际上,LightGBM 与 PySpark 的集成更无缝,能原生处理分类特征,并且可以更高效地扩展

在这篇文章中,我将分享如何在一个为财务记录中的逾期付款而构建的 PySpark 预测流水线中,用 LightGBM 替换 XGBoost。在此过程中,你将学到:

  • 为什么 LightGBM 在 Spark 中通常比 XGBoost 更适合
  • 如何清晰地预处理分类和数值特征
  • 如何使用 mmlspark 在 PySpark 中配置和训练 LightGBM 流水线
  • 如何使用 MLflow 跟踪实验
  • 如何使用加权指标(例如 MAE)评估结果

这不仅仅是一次代码演练。这是一份基于处理 Spark 中数百万条记录的实际经验而形成的、经过实战检验的指南。

1 为什么预测逾期付款(或任何业务指标)很困难

预测业务结果看起来出奇地简单:获取历史数据,拟合模型,预测未来。但如果你曾处理过混乱的企业数据,你就会知道真相:

  • 分类混乱:ID、产品代码和公司代码通常有数千甚至数百万个唯一值。
  • 数据不平衡:有些客户总是按时付款,有些则很少——模型很容易出现偏差。
  • 计算量大:即使是“小型”企业数据集,当跨越数年时,也可能达到数亿行。
  • 动态环境:宏观经济冲击、季节性周期和政策变化都可能改变目标。

传统回归模型在这种重压下会崩溃。这就是 Boosting 算法大显身手的地方——它们能捕捉非线性、交互作用和鲁棒性。

但在 XGBoostLightGBM 之间,它们与 PySpark 的配合方式却大相径庭。

2 开始之前:快速回顾

在那篇文章(90% 的机器学习团队仍停留在 2019 年的建模方式: Spark+XGBoost大规模训练)中,我一步步地向你展示了如何使用 PySpark 和 XGBoost——处理分类变量、组装特征以及大规模训练预测模型。

那篇文章为许多希望将 XGBoost 引入 Spark ML 流水线的数据科学家奠定了基础。

但在生产环境中对大型数据集运行后,我开始注意到痛点

  • 使用 VectorAssembler 进行特征组装很麻烦。
  • 分类变量的独热编码导致大规模特征爆炸
  • 当运行按国家划分的模型时,训练时间比预期要长得多。

这些限制促使我探索 LightGBM,这也是本文的重点。

💡 如果你还没有阅读 XGBoost 的文章,不用担心——本文是独立的。但如果你想了解完整的历程,我建议从那里开始。

3 为什么在 PySpark 中选择 LightGBM 而非 XGBoost?

当我最初构建预测流水线时,我使用了 XGBoost。模型运行良好——预测合理,指标可接受。但随着流水线的增长,问题开始显现:

  • VectorAssembler 开销:XGBoost 要求所有特征都组合成一个单一的向量列。对于宽数据集,这意味着巨大的转换开销。
  • 编码噩梦:处理高基数分类变量迫使我进行独热编码(导致特征空间爆炸)或手动频率编码。
  • 训练时间:即使采用分布式训练,Spark-XGBoost 集成感觉比预期慢。

LightGBM 通过 mmlspark 登场

  • 直接的分类支持:LightGBM 直接接受索引化的分类变量,而不是独热编码。
  • 内存效率:它使用基于直方图的学习,显著减少了内存需求。
  • 流水线友好:它像任何其他 Spark ML 阶段一样工作,因此可以轻松融入现有工作流。
  • 速度:在我的逾期付款数据集上,训练时间比 XGBoost 减少了约 30%。

💡 关键洞察:如果你已经在 PySpark 中,LightGBM 让你保持“Spark 原生”,而不是强行引入一个并非为分布式流水线设计的库。

4 LightGBM 如何改善欧洲地区的运行时性能

我面临的最大挑战之一,不仅仅是构建一个单一的预测模型——而是将其扩展到数十个欧洲国家,每个国家都有自己的法规、业务部门和客户行为

最初,使用 XGBoost 时,我尝试了两种方法:

  1. 一个全球模型,在所有国家/地区的数据上进行训练。

    • 问题:性能差异很大。发票量较小的国家被较大的国家(例如德国与斯洛伐克)所掩盖。
    • 训练时间膨胀,因为特征空间庞大且异构。
  2. 每个国家一个模型,按顺序训练。

    • 问题:总运行时间非常慢。训练 25-30 个国家/地区特定模型需要数小时。

这就是 LightGBM + PySpark 流水线真正改变游戏规则的地方。

4.1 LightGBM 带来了哪些变化

  • 原生分类处理:LightGBM 直接处理索引化的类别,而不是对数千个国家或客户特定类别进行独热编码。这显著减少了预处理时间。
  • Spark 中的并行训练:通过按国家/地区拆分数据并将作业分发到 Spark 执行器,我能够并行训练特定国家/地区的模型
  • 更快的训练算法:LightGBM 基于直方图的学习缩短了迭代时间,尤其是在供应商或产品代码等高基数特征上。

4.2 结果


我使用的国家/地区的耗时比较

  • 对于全套欧洲模型,运行时间从 XGBoost 的约 6 小时缩短到 LightGBM 的不到 2 小时
  • 一致性提高:每个国家都有自己的调优模型,而不会牺牲周转时间。
  • 灵活性增加:当新国家加入时,我可以启动一个模型,而无需重新训练整个全球流水线。

5 步骤 1:准备特征

PySpark 中的预处理通常是项目成功或失败的关键。对于 LightGBM,好消息是您不需要复杂的组装器。

我们首先使用 StringIndexer 对分类列进行索引:

stages = []
lightgbm_features_input_cols = []

indexed_categorical_output_cols = [c + "_indexed" for c in categorical_cols]
for i, cat_col in enumerate(categorical_cols):
    indexer = StringIndexer(
        inputCol=cat_col,
        outputCol=indexed_categorical_output_cols[i],
        handleInvalid="keep"
    )
    stages.append(indexer)

lightgbm_features_input_cols.extend(numerical_cols)
lightgbm_features_input_cols.extend(indexed_categorical_output_cols)

👉 对于 XGBoost,您必须将这些特征组装成一个单一的密集向量。对于 LightGBM,流水线保持更简单、更透明。

专业提示:始终使用 handleInvalid="keep" 以防止在评分过程中出现未见类别的问题。

6 步骤 2:在 PySpark 中配置 LightGBM

这就是奇迹发生的地方。如果你以前调整过 XGBoost,参数看起来会很熟悉。

from mmlspark.lightgbm import LightGBMRegressor

params_lgb = {
    'objective': 'regression_l1',
    'learningRate': 0.03,
    'numIterations': 600,
    'numLeaves': 31,
    'maxDepth': 6,
    'featureFraction': 0.7,
    'baggingFraction': 0.5,
    'baggingFreq': 1,
    'lambdaL1': 0.35,
    'lambdaL2': 0.3,
    'metric': 'mae',
    'seed': 1234,
    'isProvidingTrainingMetric': True,
    'featuresCol': lightgbm_features_input_cols,
    'labelCol': 'Overdue_Days',
    'weightCol': 'W_Amount',
    'validationIndicatorCol': 'validation_0',
    'earlyStoppingRound': 30
}

sparkLgb = LightGBMRegressor(**params_lgb)
stages.append(sparkLgb)

注意两点:

  1. ValidationIndicatorCol — PySpark 中 LightGBM 独有的。它允许您在一个 DataFrame 中混合训练集和验证集。
  2. 加权学习 — 使用 weightCol="W_Amount" 确保模型优先预测具有更高财务影响的样本。

这在信用风险或应收账款预测中非常强大,因为错误分类一张 1 美元的发票与错误分类一张 100 万美元的发票不同。

7 步骤 3:划分训练集和验证集

LightGBM 期望一个带有二进制列标记验证行的单一数据集,而不是单独的数据集。

train, test = train_df_historical.randomSplit([0.8, 0.2], seed=0)

train_with_indicator = train.withColumn("validation_0", lit(False))
test_with_indicator = test.withColumn("validation_0", lit(True))
combined_df = train_with_indicator.unionByName(test_with_indicator)

👉 如果你忘记了这一点,LightGBM 将不知道何时提前停止——即使是经验丰富的 Spark 用户,这也是一个常见的错误。

8 步骤 4:使用 MLflow 进行训练和日志记录

在 Databricks(或任何 Spark + MLflow 环境)中工作最好的部分之一是可重现性。每个模型拟合都可以被记录和比较。

from pyspark.ml import Pipeline
import mlflow

pipeline = Pipeline().setStages(stages)

print("--- Starting Pipeline Fit ---")
model_lgb_pipeline = pipeline.fit(combined_df)
mlflow.spark.log_model(model_lgb_pipeline, "spark-model")
print("--- Pipeline Fit Complete ---")

现在您有一个版本化、可重用的模型存储在 MLflow 中。您可以跟踪指标、参数,甚至稍后直接从 MLflow 部署流水线。

9 步骤 5:预测和评估

预测看起来像任何其他 Spark ML 模型:

predictions_test_df = model_lgb_pipeline.transform(test_df_forecast)

predictions_test_df.select(
    'Accounting_Document',
    'Overdue_Days',
    "prediction",
    "Amount",
    'Clearing_Date'
).show(10, truncate=False)

对于评估,我使用了平均绝对误差 (MAE)——按发票金额加权:

from pyspark.ml.evaluation import RegressionEvaluator
from pyspark.sql.functions import col

evaluated_predictions_df = predictions_test_df.filter(col('Clearing_Date').isNotNull())

evaluator = RegressionEvaluator(
    labelCol="Overdue_Days",
    predictionCol="prediction",
    metricName="mae",
    weightCol="W_Amount"
)
mae_test = evaluator.evaluate(evaluated_predictions_df)
print(f"\nMean Absolute Error (MAE): {mae_test}")

在我的实验中,LightGBM 始终比 XGBoost 提供更低的 MAE 和更短的训练时间

10 实际影响

在一个项目中,我们使用这个流水线预测了数百万张发票中数百个客户的逾期天数。业务影响是显而易见的:

  • 现金流预测比旧模型提高了 15%
  • 催收团队效率提高,因为预测优先处理了风险最高、价值最高的发票。
  • 模型再训练时间从数小时缩短到数分钟,这得益于 Spark + LightGBM 的集成。

这不仅仅是一次技术上的胜利——它重塑了财务和风险团队的日常工作方式。

11 常见错误及规避方法

即使使用 LightGBM,仍然存在一些陷阱:

  1. 跳过 validationIndicatorCol — 没有提前停止,训练时间更长。
  2. 独热编码类别 — 在 LightGBM 中不必要且效率低下。
  3. 使用默认的叶子数和深度 — 可能导致欠拟合;始终调整 numLeavesmaxDepth
  4. 忽略权重 — 如果财务价值不同,不加权的 MAE 将产生误导。
  5. 不记录实验 — 没有 MLflow,您将失去可重现性和可比较性。

12 趋势与展望

  • AutoML 遇见 Spark:Databricks AutoML 等工具很快将更无缝地集成 LightGBM 流水线。
  • 可解释性:SHAP 和特征归因正在成为标准,即使在 Spark 中也是如此。预计将出现“开箱即用”的特征重要性图表集成。
  • 混合方法:结合 LightGBM 处理表格数据 + Transformer 模型处理文本/非结构化数据(例如,分析付款备注和发票)。
  • 监管推动:在金融领域,现在需要可解释和可审计的模型。Spark 中的 LightGBM 满足了这两个要求。

13 关键要点

  • LightGBM 比 XGBoost 更自然地融入 PySpark 流水线。
  • 它直接处理分类特征,减少了工程开销。
  • 验证指标是高效训练和提前停止的关键。
  • 加权指标确保您的模型与业务优先级保持一致。
  • 在 MLflow 中进行日志记录使您的工作可重现和可部署。

网站公告

今日签到

点亮在社区的每一天
去签到