下面是一个使用 PySpark库包 训练 XGBoost 模型的详细步骤指南,包含模拟数据生成和完整代码。
由于 PySpark 本身不直接支持 XGBoost, 我们将使用 sparkxgb 包(XGBoost4J-Spark 的 Python 包装器)。
这里需要重点说明一下:
(Spark原生MLlib并不直接支持XGBoost算法),
(Spark原生MLlib是支持随机森林模型算法的, 如 from pyspark.ml.classification import RandomForestClassifier)
先决条件
安装必要的包:
pip install xgboost==1.7.6 pyspark==3.4.1 sparkxgb==0.4.1
完整代码示例
from pyspark.sql import SparkSession
from pyspark.ml.feature import VectorAssembler
from sparkxgb import XGBoostClassifier # 注意:需要安装sparkxgb
from pyspark.ml.evaluation import BinaryClassificationEvaluator, MulticlassClassificationEvaluator
import numpy as np
import pandas as pd
# 步骤 1:初始化 Spark 会话
spark = SparkSession.builder \
.appName("XGBoost-Example") \
.config("spark.jars.packages", "ml.dmlc:xgboost4j-spark_2.12:1.7.6") \
.config("spark.driver.memory", "4g") \
.getOrCreate()
# 步骤 2:生成模拟数据
def generate_data(n_samples=10000, seed=42):
np.random.seed(seed)
data = {
'age': np.random.randint(18, 70, n_samples),
'income': np.random.normal(50000, 15000, n_samples),
'credit_score': np.random.randint(300, 850, n_samples),
'debt_ratio': np.random.uniform(0.1, 0.8, n_samples),
'existing_loans': np.random.poisson(2, n_samples),
'default': np.random.binomial(1, 0.3, n_samples) # 30% 的违约概率
}
# 添加一些特征交互
data['risk_factor'] = data['age'] * 0.1 + data['debt_ratio'] * 5
data['affordability'] = data['income'] / (data['existing_loans'] + 1) * 0.01
return pd.DataFrame(data)
# 创建 10,000 个样本
pdf = generate_data(n_samples=10000)
df = spark.createDataFrame(pdf)
# 查看数据结构
print("数据样例:")
df.show(5)
print(f"数据集大小: {df.count()} 行")
# 步骤 3:数据预处理
# 选择特征列
feature_cols = ['age', 'income', 'credit_score', 'debt_ratio', 'existing_loans', 'risk_factor', 'affordability']
# 创建特征向量
assembler = VectorAssembler(
inputCols=feature_cols,
outputCol="features"
)
df = assembler.transform(df).select("features", "default")
# 重命名标签列(XGBoost要求标签列名为"label")
df = df.withColumnRenamed("default", "label")
# 步骤 4:划分训练集/测试集
train_ratio, test_ratio = 0.8, 0.2
train_data, test_data = df.randomSplit([train_ratio, test_ratio], seed=42)
print(f"训练集数量: {train_data.count()}")
print(f"测试集数量: {test_data.count()}")
# 步骤 5:配置并训练 XGBoost 模型
xgb = XGBoostClassifier(
featuresCol="features",
labelCol="label",
numWorkers=2, # 并行工作节点数
nthread=4, # 每个worker的线程数
numRound=100, # 提升轮数(树的数量)
maxDepth=6, # 最大深度
eta=0.3, # 学习率
subsample=0.8, # 样本采样率
colsampleBytree=0.8, # 特征采样率
objective="binary:logistic", # 二分类目标函数
eval_metric="auc", # 评估指标
earlyStoppingRounds=10, # 早停轮数
seed=42
)
# 训练模型
model = xgb.fit(train_data)
# 步骤 6:模型评估
# 在测试集上进行预测
predictions = model.transform(test_data)
# 显示预测结果
print("\n预测结果样例:")
predictions.select("label", "prediction", "probability").show(10, truncate=False)
# 计算评估指标
# 1. 准确率
evaluator_acc = MulticlassClassificationEvaluator(
labelCol="label",
predictionCol="prediction",
metricName="accuracy"
)
accuracy = evaluator_acc.evaluate(predictions)
# 2. AUC
evaluator_auc = BinaryClassificationEvaluator(
labelCol="label",
rawPredictionCol="rawPrediction",
metricName="areaUnderROC"
)
auc = evaluator_auc.evaluate(predictions)
# 3. F1 分数
evaluator_f1 = MulticlassClassificationEvaluator(
labelCol="label",
predictionCol="prediction",
metricName="f1"
)
f1 = evaluator_f1.evaluate(predictions)
print("\n模型评估结果:")
print(f"测试集准确率: {accuracy:.4f}")
print(f"AUC 值: {auc:.4f}")
print(f"F1 分数: {f1:.4f}")
# 步骤 7:特征重要性分析
feature_importances = model.nativeBooster().get_score(importance_type='weight')
print("\n特征重要性:")
for feature, importance in sorted(feature_importances.items(), key=lambda x: x[1], reverse=True):
print(f"{feature}: {importance}")
# 步骤 8:模型保存与加载(可选)
model_path = "xgboost_model"
model.write().overwrite().save(model_path)
print(f"\n模型已保存到: {model_path}")
# 加载模型示例
# from sparkxgb import XGBoostClassificationModel
# loaded_model = XGBoostClassificationModel.load(model_path)
# 步骤 9:停止 Spark 会话
spark.stop()
详细步骤说明
-
环境准备
- 初始化 SparkSession 并配置 XGBoost 依赖
- 指定
spark.jars.packages加载 XGBoost4J-Spark 库 - 分配足够内存(根据数据集大小调整)
-
数据生成
- 创建包含 7 个特征的模拟金融数据集:
- 年龄、收入、信用评分、债务比率
- 现有贷款数量、风险因子、可负担性
- 目标变量:
default(是否违约) - 添加了特征交互增强数据真实性
- 创建包含 7 个特征的模拟金融数据集:
-
数据预处理
- 使用
VectorAssembler将特征列合并为特征向量 - 重命名目标列为
label(XGBoost 要求) - 数据格式转换:DataFrame → 特征向量
- 使用
-
数据划分
- 按 80:20 比例划分训练集/测试集
- 设置随机种子确保可复现性
-
模型配置
- 关键参数说明:
numWorkers:并行执行器数量(根据集群规模设置)numRound:树的数量(提升迭代次数)maxDepth:单棵树的最大深度eta:学习率(控制过拟合)subsample:样本采样率(随机森林特性)colsampleBytree:特征采样率earlyStoppingRounds:验证集性能不再提升时提前停止
- 关键参数说明:
-
模型训练
- 使用
fit()方法训练模型 - 训练过程自动处理特征向量格式
- 使用
-
模型评估
- 计算三大关键指标:
- 准确率(Accuracy)
- AUC(衡量排序能力)
- F1 分数(平衡精确率与召回率)
- 展示预测概率分布
- 计算三大关键指标:
-
特征重要性
- 使用
get_score()方法获取特征重要性 - 按重要性降序排列特征
- 使用
-
模型部署
- 使用 Spark ML 的保存/加载机制
- 支持分布式存储(HDFS/S3)
参数调优建议
-
学习率 (eta)
- 典型范围:[0.01, 0.3]
- 较低值:更稳健但需要更多树
- 较高值:更快收敛但可能过拟合
-
树的数量 (numRound)
- 与学习率配合:
eta越小,需要越多树 - 使用早停自动确定最优树数量
- 与学习率配合:
-
正则化参数
lambda:L2 正则化(默认 1)alpha:L1 正则化(默认 0)- 增加这些值可减少过拟合
-
采样参数
subsample:控制每棵树使用的样本比例colsampleBytree:控制每棵树使用的特征比例- 典型值:[0.7, 0.9]
性能优化技巧
-
数据缓存
train_data.cache() # 缓存训练数据加速迭代 -
并行度调整
- 增加
numWorkers到集群执行器数量 - 设置
nthread为每个 worker 的 CPU 核心数
- 增加
-
特征工程
- 添加交互特征(如代码中的 risk_factor)
- 对连续特征进行分桶
- 标准化数值特征
-
分布式训练
# 在集群配置中添加 .config("spark.task.cpus", "4") # 每个任务CPU核心 .config("spark.executor.instances", "8") # 执行器数量
典型输出示例
数据样例:
+---+------+------------+----------+-------------+----------+------------+-------+
|age|income|credit_score|debt_ratio|existing_loans|risk_factor|affordability|default|
+---+------+------------+----------+-------------+----------+------------+-------+
| 51| 62305| 623| 0.4135| 2| 4.535| 311.525| 0|
| 34| 32980| 582| 0.6512| 1| 6.256| 329.800| 1|
| 68| 45992| 712| 0.2467| 0| 4.467| 459.920| 0|
+---+------+------------+----------+-------------+----------+------------+-------+
训练集数量: 7982
测试集数量: 2018
预测结果样例:
+-----+----------+---------------------------------------+
|label|prediction|probability |
+-----+----------+---------------------------------------+
|0 |0.0 |[0.8132284283638,0.18677155673503876] |
|1 |1.0 |[0.2102809101343155,0.7897191047668457]|
|0 |0.0 |[0.7243872880935669,0.2756127119064331]|
+-----+----------+---------------------------------------+
模型评估结果:
测试集准确率: 0.7823
AUC 值: 0.8617
F1 分数: 0.7124
特征重要性:
f5: 142.0 # affordability
f2: 120.0 # income
f4: 98.0 # risk_factor
f3: 85.0 # credit_score
f1: 76.0 # age
f0: 65.0 # debt_ratio
f6: 52.0 # existing_loans
模型已保存到: xgboost_model
常见问题解决
-
ClassNotFoundException
- 确保
spark.jars.packages配置正确 - 检查 Scala 版本兼容性(通常为 2.12)
- 确保
-
内存不足
- 增加 driver/executor 内存:
.config("spark.driver.memory", "8g") .config("spark.executor.memory", "8g")
- 增加 driver/executor 内存:
-
性能优化
- 对连续特征进行分桶
- 减少分类特征的基数
- 使用
persist(StorageLevel.MEMORY_AND_DISK)缓存数据
-
处理类别特征
from pyspark.ml.feature import StringIndexer indexer = StringIndexer(inputCol="category", outputCol="categoryIndex") df = indexer.fit(df).transform(df) # 然后将 categoryIndex 加入特征向量
这个流程提供了完整的 XGBoost 模型训练实现,从数据生成到模型评估,适用于二分类问题。对于回归或多分类问题,只需调整 objective 参数(如 reg:squarederror 或 multi:softmax)。