未记录事实核验 · 状态:维护中
记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。
warning 适用边界与维护说明
本文适合作为 Spark ML 特征工程、算法配置、模型评估调优、持久化和批量推理的高级实践参考,不是可直接运行的完整项目。实战 FeatureEngineeringPipeline 仍将 TF-IDF 与标准化连续数值特征合并后送入 ChiSqSelector,未满足卡方选择的类别型特征前提,不宜直接照用该步骤。模型比较缺少随机森林和 GBT 的 Pipeline 构建方法;流式示例缺少 Kafka 接入、数据 schema、已拟合特征模型、当前模型及重训练与切换实现,监控指标发送函数也需自行提供;mapValues 的返回类型须按实际 Scala 版本适配。重训练方法已明确为在新数据上重新批量拟合,并非延续旧模型状态的增量学习;软投票应输入非空预测集合,并保持二分类标签映射一致、id 唯一且样本集合一致。GBTClassifier、LinearSVC 及 AUC 相关示例按二分类使用,保存和加载模型不包含在线服务部署。本次仅作全文结构审阅,未进行代码运行测试或外部事实核验。
MLlib机器学习
概述
MLlib是Apache Spark的分布式机器学习库,提供了丰富的机器学习算法和工具。它建立在Spark Core之上,能够处理大规模数据集的机器学习任务,支持分类、回归、聚类、协同过滤等多种学习任务。
info 设计理念
MLlib的设计目标是让机器学习算法能够轻松扩展到大数据场景,同时保持易用性和高性能。它提供了两套API:基于RDD的原始API和基于DataFrame的ML Pipeline API。
核心架构
MLlib组件结构
%%{init: {"theme":"base","themeVariables":{"fontFamily":"PingFang SC, -apple-system, Source Han Serif SC, serif","fontSize":"16px","background":"#FDFBF5","primaryColor":"#FDFBF5","primaryTextColor":"#2D2A26","primaryBorderColor":"#6E6A60","secondaryColor":"#E8EFE8","secondaryBorderColor":"#8FA890","secondaryTextColor":"#2D2A26","tertiaryColor":"#FDFBF5","tertiaryBorderColor":"#9A9488","tertiaryTextColor":"#6E6A60","lineColor":"#6E6A60","textColor":"#2D2A26","mainBkg":"#FDFBF5","nodeBorder":"#2D5A3D","clusterBkg":"#F3EEDF","clusterBorder":"#9A9488","edgeLabelBackground":"#FDFBF5"},"flowchart":{"htmlLabels":true,"curve":"basis","padding":20,"nodeSpacing":60,"rankSpacing":70,"useMaxWidth":false},"themeCSS":".node rect, .node polygon, .node circle { stroke-width: 1.5px; } .edgePath .path { stroke-width: 1.5px; } .cluster-label .nodeLabel, .cluster-label foreignObject { color: #2D2A26 !important; } .edgeLabel, .edgeLabel foreignObject { color: #2D2A26 !important; background-color: #FDFBF5; } .edgeLabel rect { fill: #FDFBF5; }"}}%%
graph TB
classDef default fill:#FDFBF5,stroke:#6E6A60,color:#2D2A26,stroke-width:1.5px
classDef startend fill:#2D2A26,stroke:#2D2A26,color:#FDFBF5,font-weight:bold
classDef decision fill:#F6EAD8,stroke:#C08A1A,color:#2D2A26,font-weight:bold
classDef hub fill:#3B5A80,stroke:#3B5A80,color:#FDFBF5,font-weight:bold
classDef io fill:#E5EAF0,stroke:#3B5A80,color:#2D2A26
classDef accent fill:#A6432C,stroke:#A6432C,color:#FDFBF5,font-weight:bold
classDef storage fill:#F3EEDF,stroke:#9A9488,color:#2D2A26
A[MLlib] --> B[ML Pipeline API]
A --> C[RDD-based API]
B --> B1[Estimators]
B --> B2[Transformers]
B --> B3[Pipeline]
B --> B4[Parameters]
C --> C1[Classification]
C --> C2[Regression]
C --> C3[Clustering]
C --> C4[Collaborative Filtering]
C --> C5[Feature Extraction]
subgraph "算法类别"
D[监督学习]
E[无监督学习]
F[推荐系统]
G[特征工程]
end
class A,B,C,B1,B2,B3,B4,C1,C2,C3,C4,C5,D,E,F,G default
ML Pipeline概念
ML Pipeline提供了构建机器学习工作流的统一API:
import org.apache.spark.ml.{Pipeline, PipelineModel}
import org.apache.spark.ml.classification.LogisticRegression
import org.apache.spark.ml.feature.{HashingTF, Tokenizer}
// 创建转换器和估计器
val tokenizer = new Tokenizer()
.setInputCol("text")
.setOutputCol("words")
val hashingTF = new HashingTF()
.setInputCol("words")
.setOutputCol("features")
.setNumFeatures(1000)
val lr = new LogisticRegression()
.setMaxIter(10)
.setRegParam(0.001)
// 构建Pipeline
val pipeline = new Pipeline()
.setStages(Array(tokenizer, hashingTF, lr))
// 训练模型
val model = pipeline.fit(trainingData)
// 预测
val predictions = model.transform(testData)
特征工程
特征提取
文本特征提取
import org.apache.spark.ml.feature._
// TF-IDF
val tokenizer = new Tokenizer()
.setInputCol("text")
.setOutputCol("words")
val hashingTF = new HashingTF()
.setInputCol("words")
.setOutputCol("rawFeatures")
.setNumFeatures(10000)
val idf = new IDF()
.setInputCol("rawFeatures")
.setOutputCol("features")
// Word2Vec
val word2Vec = new Word2Vec()
.setInputCol("words")
.setOutputCol("wordVectors")
.setVectorSize(100)
.setMinCount(5)
// CountVectorizer
val countVectorizer = new CountVectorizer()
.setInputCol("words")
.setOutputCol("features")
.setVocabSize(10000)
.setMinDF(2)
数值特征处理
// StandardScaler - 标准化
val scaler = new StandardScaler()
.setInputCol("features")
.setOutputCol("scaledFeatures")
.setWithStd(true)
.setWithMean(false)
// MinMaxScaler - 归一化
val minMaxScaler = new MinMaxScaler()
.setInputCol("features")
.setOutputCol("scaledFeatures")
.setMin(0.0)
.setMax(1.0)
// Normalizer - 向量归一化
val normalizer = new Normalizer()
.setInputCol("features")
.setOutputCol("normFeatures")
.setP(2.0) // L2范数
// Bucketizer - 分桶
val bucketizer = new Bucketizer()
.setInputCol("features")
.setOutputCol("bucketedFeatures")
.setSplits(Array(Double.NegativeInfinity, -0.5, 0.0, 0.5, Double.PositiveInfinity))
特征选择
// VectorSlicer - 特征切片
val vectorSlicer = new VectorSlicer()
.setInputCol("features")
.setOutputCol("selectedFeatures")
.setIndices(Array(1, 4, 5))
// ChiSqSelector - 卡方特征选择
val chiSqSelector = new ChiSqSelector()
.setNumTopFeatures(10)
.setFeaturesCol("features")
.setLabelCol("label")
.setOutputCol("selectedFeatures")
// VarianceThresholdSelector - 方差阈值选择
val varianceSelector = new VarianceThresholdSelector()
.setFeaturesCol("features")
.setOutputCol("selectedFeatures")
.setVarianceThreshold(0.1)
特征转换
// StringIndexer - 字符串索引
val stringIndexer = new StringIndexer()
.setInputCol("category")
.setOutputCol("categoryIndex")
// OneHotEncoder - 独热编码
val oneHotEncoder = new OneHotEncoder()
.setInputCol("categoryIndex")
.setOutputCol("categoryVec")
// VectorAssembler - 特征组合
val assembler = new VectorAssembler()
.setInputCols(Array("feature1", "feature2", "feature3"))
.setOutputCol("features")
// PCA - 主成分分析
val pca = new PCA()
.setInputCol("features")
.setOutputCol("pcaFeatures")
.setK(3)
分类算法
逻辑回归
import org.apache.spark.ml.classification.LogisticRegression
import org.apache.spark.ml.evaluation.BinaryClassificationEvaluator
// 创建逻辑回归模型
val lr = new LogisticRegression()
.setMaxIter(20)
.setRegParam(0.01)
.setElasticNetParam(0.8)
.setFeaturesCol("features")
.setLabelCol("label")
// 训练模型
val lrModel = lr.fit(trainingData)
// 预测
val predictions = lrModel.transform(testData)
// 评估
val evaluator = new BinaryClassificationEvaluator()
.setLabelCol("label")
.setRawPredictionCol("rawPrediction")
.setMetricName("areaUnderROC")
val auc = evaluator.evaluate(predictions)
println(s"AUC: $auc")
// 查看模型系数
println(s"Coefficients: ${lrModel.coefficients}")
println(s"Intercept: ${lrModel.intercept}")
随机森林
import org.apache.spark.ml.classification.RandomForestClassifier
import org.apache.spark.ml.evaluation.MulticlassClassificationEvaluator
val rf = new RandomForestClassifier()
.setNumTrees(100)
.setMaxDepth(5)
.setMaxBins(32)
.setMinInstancesPerNode(1)
.setMinInfoGain(0.0)
.setSubsamplingRate(1.0)
.setFeatureSubsetStrategy("auto")
.setSeed(12345)
val rfModel = rf.fit(trainingData)
val predictions = rfModel.transform(testData)
// 多类分类评估
val evaluator = new MulticlassClassificationEvaluator()
.setLabelCol("label")
.setPredictionCol("prediction")
.setMetricName("accuracy")
val accuracy = evaluator.evaluate(predictions)
println(s"Accuracy: $accuracy")
// 特征重要性
println(s"Feature Importances: ${rfModel.featureImportances}")
梯度提升树
import org.apache.spark.ml.classification.GBTClassifier
val gbt = new GBTClassifier()
.setMaxIter(10)
.setMaxDepth(5)
.setStepSize(0.1)
.setMinInstancesPerNode(1)
.setMinInfoGain(0.0)
.setSubsamplingRate(1.0)
.setFeatureSubsetStrategy("all")
val gbtModel = gbt.fit(trainingData)
val predictions = gbtModel.transform(testData)
支持向量机
import org.apache.spark.ml.classification.LinearSVC
val svm = new LinearSVC()
.setMaxIter(100)
.setRegParam(0.01)
.setTol(1e-6)
.setFitIntercept(true)
.setStandardization(true)
.setThreshold(0.0)
val svmModel = svm.fit(trainingData)
val predictions = svmModel.transform(testData)
回归算法
线性回归
import org.apache.spark.ml.regression.LinearRegression
import org.apache.spark.ml.evaluation.RegressionEvaluator
val lr = new LinearRegression()
.setMaxIter(10)
.setRegParam(0.3)
.setElasticNetParam(0.8)
.setFeaturesCol("features")
.setLabelCol("label")
val lrModel = lr.fit(trainingData)
// 模型摘要
val trainingSummary = lrModel.summary
println(s"RMSE: ${trainingSummary.rootMeanSquaredError}")
println(s"R2: ${trainingSummary.r2}")
println(s"Mean Absolute Error: ${trainingSummary.meanAbsoluteError}")
// 预测和评估
val predictions = lrModel.transform(testData)
val evaluator = new RegressionEvaluator()
.setLabelCol("label")
.setPredictionCol("prediction")
.setMetricName("rmse")
val rmse = evaluator.evaluate(predictions)
println(s"Root Mean Squared Error (RMSE) on test data = $rmse")
随机森林回归
import org.apache.spark.ml.regression.RandomForestRegressor
val rf = new RandomForestRegressor()
.setNumTrees(20)
.setMaxDepth(5)
.setMaxBins(32)
.setMinInstancesPerNode(1)
.setMinInfoGain(0.0)
.setSubsamplingRate(1.0)
.setFeatureSubsetStrategy("onethird")
val rfModel = rf.fit(trainingData)
val predictions = rfModel.transform(testData)
决策树回归
import org.apache.spark.ml.regression.DecisionTreeRegressor
val dt = new DecisionTreeRegressor()
.setMaxDepth(5)
.setMaxBins(32)
.setMinInstancesPerNode(1)
.setMinInfoGain(0.0)
.setVarianceCol("variance")
val dtModel = dt.fit(trainingData)
val predictions = dtModel.transform(testData)
聚类算法
K-Means聚类
import org.apache.spark.ml.clustering.KMeans
import org.apache.spark.ml.evaluation.ClusteringEvaluator
// K-Means
val kmeans = new KMeans()
.setK(3)
.setMaxIter(20)
.setTol(1e-4)
.setDistanceMeasure("euclidean")
.setFeaturesCol("features")
.setPredictionCol("cluster")
val kmeansModel = kmeans.fit(dataset)
// 预测
val predictions = kmeansModel.transform(dataset)
// 评估 - 轮廓系数
val evaluator = new ClusteringEvaluator()
.setFeaturesCol("features")
.setPredictionCol("cluster")
.setMetricName("silhouette")
.setDistanceMeasure("squaredEuclidean")
val silhouette = evaluator.evaluate(predictions)
println(s"Silhouette with squared euclidean distance = $silhouette")
// 聚类中心
println("Cluster Centers:")
kmeansModel.clusterCenters.foreach(println)
// 类内误差平方和
val wssse = kmeansModel.summary.trainingCost
println(s"Within Set Sum of Squared Errors = $wssse")
高斯混合模型
import org.apache.spark.ml.clustering.GaussianMixture
val gmm = new GaussianMixture()
.setK(2)
.setMaxIter(100)
.setTol(1e-6)
.setFeaturesCol("features")
.setPredictionCol("cluster")
.setProbabilityCol("probability")
val gmmModel = gmm.fit(dataset)
// 预测
val predictions = gmmModel.transform(dataset)
// 模型参数
println("Weights:")
gmmModel.weights.foreach(println)
println("Gaussians:")
for (i <- gmmModel.gaussians.indices) {
println(s"Gaussian $i:")
println(s"Mean: ${gmmModel.gaussians(i).mean}")
println(s"Covariance: ${gmmModel.gaussians(i).cov}")
}
层次聚类
import org.apache.spark.ml.clustering.BisectingKMeans
val bkm = new BisectingKMeans()
.setK(4)
.setMaxIter(20)
.setMinDivisibleClusterSize(1)
.setDistanceMeasure("euclidean")
val bkmModel = bkm.fit(dataset)
val predictions = bkmModel.transform(dataset)
// 打印聚类中心
println("Cluster Centers:")
bkmModel.clusterCenters.foreach(println)
协同过滤
交替最小二乘法 (ALS)
import org.apache.spark.ml.recommendation.ALS
import org.apache.spark.ml.evaluation.RegressionEvaluator
// 准备数据 - 用户ID、物品ID、评分
case class Rating(userId: Int, movieId: Int, rating: Float, timestamp: Long)
// 创建ALS模型
val als = new ALS()
.setMaxIter(10)
.setRegParam(0.1)
.setRank(10)
.setUserCol("userId")
.setItemCol("movieId")
.setRatingCol("rating")
.setColdStartStrategy("drop")
.setNonnegative(true)
val alsModel = als.fit(trainingData)
// 预测
val predictions = alsModel.transform(testData)
// 评估
val evaluator = new RegressionEvaluator()
.setMetricName("rmse")
.setLabelCol("rating")
.setPredictionCol("prediction")
val rmse = evaluator.evaluate(predictions)
println(s"Root-mean-square error = $rmse")
// 为所有用户推荐物品
val userRecs = alsModel.recommendForAllUsers(10)
userRecs.show(false)
// 为所有物品推荐用户
val movieRecs = alsModel.recommendForAllItems(10)
movieRecs.show(false)
// 为特定用户推荐
val users = dataset.select(als.getUserCol).distinct().limit(3)
val userSubsetRecs = alsModel.recommendForUserSubset(users, 10)
userSubsetRecs.show(false)
频繁模式挖掘
FP-Growth
import org.apache.spark.ml.fpm.FPGrowth
// 数据格式:每行是一个事务,包含物品列表
val dataset = spark.createDataFrame(Seq(
(0, Array("a", "b", "c")),
(1, Array("a", "b")),
(2, Array("a", "b", "c", "e")),
(3, Array("a", "c", "e")),
(4, Array("b", "e"))
)).toDF("id", "items")
val fpgrowth = new FPGrowth()
.setItemsCol("items")
.setMinSupport(0.5)
.setMinConfidence(0.6)
val model = fpgrowth.fit(dataset)
// 频繁项集
model.freqItemsets.show()
// 关联规则
model.associationRules.show()
// 预测
model.transform(dataset).show()
模型评估与调优
交叉验证
import org.apache.spark.ml.tuning.{CrossValidator, ParamGridBuilder}
import org.apache.spark.ml.evaluation.BinaryClassificationEvaluator
// 构建参数网格
val paramGrid = new ParamGridBuilder()
.addGrid(lr.regParam, Array(0.1, 0.01))
.addGrid(lr.maxIter, Array(10, 20))
.addGrid(lr.elasticNetParam, Array(0.0, 0.5, 1.0))
.build()
// 创建交叉验证器
val cv = new CrossValidator()
.setEstimator(lr)
.setEvaluator(new BinaryClassificationEvaluator())
.setEstimatorParamMaps(paramGrid)
.setNumFolds(5)
.setParallelism(2)
// 训练模型
val cvModel = cv.fit(trainingData)
// 使用最佳模型预测
val predictions = cvModel.transform(testData)
// 获取最佳参数
val bestModel = cvModel.bestModel.asInstanceOf[LogisticRegressionModel]
println(s"Best RegParam: ${bestModel.getRegParam}")
println(s"Best MaxIter: ${bestModel.getMaxIter}")
训练验证分割
import org.apache.spark.ml.tuning.{TrainValidationSplit, ParamGridBuilder}
val trainValidationSplit = new TrainValidationSplit()
.setEstimator(lr)
.setEvaluator(new BinaryClassificationEvaluator())
.setEstimatorParamMaps(paramGrid)
.setTrainRatio(0.8)
val tvModel = trainValidationSplit.fit(trainingData)
val predictions = tvModel.transform(testData)
评估指标
import org.apache.spark.ml.evaluation._
// 二分类评估
val binaryEvaluator = new BinaryClassificationEvaluator()
.setLabelCol("label")
.setRawPredictionCol("rawPrediction")
val areaUnderROC = binaryEvaluator.setMetricName("areaUnderROC").evaluate(predictions)
val areaUnderPR = binaryEvaluator.setMetricName("areaUnderPR").evaluate(predictions)
// 多类分类评估
val multiclassEvaluator = new MulticlassClassificationEvaluator()
.setLabelCol("label")
.setPredictionCol("prediction")
val accuracy = multiclassEvaluator.setMetricName("accuracy").evaluate(predictions)
val f1Score = multiclassEvaluator.setMetricName("f1").evaluate(predictions)
val precision = multiclassEvaluator.setMetricName("weightedPrecision").evaluate(predictions)
val recall = multiclassEvaluator.setMetricName("weightedRecall").evaluate(predictions)
// 回归评估
val regressionEvaluator = new RegressionEvaluator()
.setLabelCol("label")
.setPredictionCol("prediction")
val rmse = regressionEvaluator.setMetricName("rmse").evaluate(predictions)
val mae = regressionEvaluator.setMetricName("mae").evaluate(predictions)
val r2 = regressionEvaluator.setMetricName("r2").evaluate(predictions)
模型持久化
保存和加载模型
import org.apache.spark.ml.classification.LogisticRegressionModel
// 保存模型
lrModel.write.overwrite().save("path/to/model")
// 加载模型
val sameModel = LogisticRegressionModel.load("path/to/model")
// 保存Pipeline模型
pipelineModel.write.overwrite().save("path/to/pipeline/model")
// 加载Pipeline模型
val samePipelineModel = PipelineModel.load("path/to/pipeline/model")
模型版本管理
// 带版本的模型保存
val modelPath = s"hdfs://namenode:8020/models/logistic_regression/v${System.currentTimeMillis()}"
lrModel.write.overwrite().save(modelPath)
// 模型元数据
case class ModelMetadata(
modelType: String,
version: String,
accuracy: Double,
trainDate: String,
features: Array[String]
)
val metadata = ModelMetadata(
"LogisticRegression",
"v1.0",
accuracy,
java.time.LocalDate.now().toString,
featureNames
)
大规模机器学习实战
特征工程Pipeline
object FeatureEngineeringPipeline {
def createPipeline(): Pipeline = {
// 1. 文本特征处理
val tokenizer = new Tokenizer()
.setInputCol("text")
.setOutputCol("words")
val stopWordsRemover = new StopWordsRemover()
.setInputCol("words")
.setOutputCol("filtered_words")
val hashingTF = new HashingTF()
.setInputCol("filtered_words")
.setOutputCol("raw_features")
.setNumFeatures(10000)
val idf = new IDF()
.setInputCol("raw_features")
.setOutputCol("text_features")
// 2. 数值特征处理
val numericCols = Array("feature1", "feature2", "feature3")
val assembler1 = new VectorAssembler()
.setInputCols(numericCols)
.setOutputCol("numeric_features")
val scaler = new StandardScaler()
.setInputCol("numeric_features")
.setOutputCol("scaled_numeric_features")
.setWithMean(true)
.setWithStd(true)
// 3. 类别特征处理
val categoricalCols = Array("category1", "category2")
val indexers = categoricalCols.map { colName =>
new StringIndexer()
.setInputCol(colName)
.setOutputCol(s"${colName}_index")
.setHandleInvalid("keep")
}
val encoders = categoricalCols.map { colName =>
new OneHotEncoder()
.setInputCol(s"${colName}_index")
.setOutputCol(s"${colName}_vec")
}
// 4. 特征组合
val finalAssembler = new VectorAssembler()
.setInputCols(Array("text_features", "scaled_numeric_features") ++
categoricalCols.map(name => s"${name}_vec"))
.setOutputCol("features")
// 5. 特征选择
val selector = new ChiSqSelector()
.setNumTopFeatures(1000)
.setFeaturesCol("features")
.setLabelCol("label")
.setOutputCol("selected_features")
new Pipeline()
.setStages(Array(tokenizer, stopWordsRemover, hashingTF, idf, assembler1, scaler) ++
indexers ++ encoders ++
Array(finalAssembler, selector))
}
}
模型比较和集成
object ModelEnsemble {
def trainMultipleModels(trainingData: DataFrame): Map[String, PipelineModel] = {
val models = Map(
"logistic_regression" -> createLogisticRegressionPipeline(),
"random_forest" -> createRandomForestPipeline(),
"gradient_boosting" -> createGBTPipeline()
)
models.mapValues(_.fit(trainingData))
}
def createLogisticRegressionPipeline(): Pipeline = {
val lr = new LogisticRegression()
.setMaxIter(100)
.setRegParam(0.01)
.setElasticNetParam(0.8)
.setFeaturesCol("selected_features")
new Pipeline().setStages(Array(
FeatureEngineeringPipeline.createPipeline(),
lr
))
}
def evaluateModels(models: Map[String, PipelineModel],
testData: DataFrame): Map[String, Double] = {
val evaluator = new BinaryClassificationEvaluator()
.setLabelCol("label")
.setRawPredictionCol("rawPrediction")
.setMetricName("areaUnderROC")
models.mapValues { model =>
val predictions = model.transform(testData)
evaluator.evaluate(predictions)
}
}
// 二分类软投票:各模型须使用一致的标签映射,且每个预测结果的 id 唯一、样本集合一致
def ensemblePredictions(predictions: Seq[DataFrame]): DataFrame = {
import org.apache.spark.sql.functions._
// 假设所有预测结果都有相同的key列
val baseDF = predictions.head.select("id", "label")
val avgPredictions = predictions.zipWithIndex.foldLeft(baseDF) {
case (df, (predDF, idx)) =>
df.join(
predDF.select("id", udf((v: org.apache.spark.ml.linalg.Vector) => v(1)).apply(col("probability")).as(s"prob_$idx")),
"id"
)
}
// 计算平均概率
val probCols = predictions.indices.map(i => col(s"prob_$i"))
avgPredictions.withColumn("ensemble_probability",
(probCols.reduce(_ + _) / probCols.length))
}
}
在线学习和增量更新
import org.apache.spark.ml.classification.LogisticRegression
import org.apache.spark.ml.feature.VectorAssembler
import org.apache.spark.streaming._
object OnlineLearning {
def retrainModelOnNewData(currentModel: LogisticRegressionModel,
newData: DataFrame): LogisticRegressionModel = {
// 复用正则化参数,在新数据上重新批量训练;不是从旧模型继续增量学习
// newData 需包含配置所要求的 features 和 label 列
val lr = new LogisticRegression()
.setMaxIter(10)
.setRegParam(currentModel.getRegParam)
.setElasticNetParam(currentModel.getElasticNetParam)
lr.fit(newData)
}
// 流式机器学习
def setupStreamingML(ssc: StreamingContext): Unit = {
val kafkaStream = createKafkaStream(ssc)
kafkaStream.foreachRDD { rdd =>
if (!rdd.isEmpty()) {
val df = spark.createDataFrame(rdd, schema)
val processedDF = featureEngineeringPipeline.transform(df)
// 批量预测
val predictions = currentModel.transform(processedDF)
// 保存预测结果
predictions.write
.mode("append")
.parquet("hdfs://path/to/predictions")
// 定期重训练模型
if (shouldRetrain()) {
val newModel = retrainModel(getRecentData())
updateCurrentModel(newModel)
}
}
}
}
}
性能优化
数据预处理优化
// 1. 数据缓存
val processedData = rawData
.filter(col("label").isNotNull)
.cache()
// 2. 分区优化
val repartitionedData = processedData
.repartition(200, col("user_id"))
// 3. 列式存储
processedData.write
.mode("overwrite")
.option("compression", "snappy")
.parquet("hdfs://path/to/processed/data")
算法参数调优
val spark = SparkSession.builder()
.appName("MLOptimization")
// 设置适当的并行度
.config("spark.sql.shuffle.partitions", "400")
// 增加执行器内存
.config("spark.executor.memory", "8g")
// 启用动态分配
.config("spark.dynamicAllocation.enabled", "true")
.config("spark.dynamicAllocation.maxExecutors", "100")
// 设置序列化器
.config("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
.getOrCreate()
最佳实践
1. 数据准备
// 数据质量检查
def checkDataQuality(df: DataFrame): Unit = {
println(s"Total rows: ${df.count()}")
println(s"Null values per column:")
df.columns.foreach { col =>
val nullCount = df.filter(df(col).isNull).count()
println(s" $col: $nullCount")
}
// 标签分布
df.groupBy("label").count().show()
}
// 数据分割
val Array(trainingData, validationData, testData) =
dataset.randomSplit(Array(0.6, 0.2, 0.2), seed = 12345)
2. 特征工程
// 特征重要性分析
def analyzeFeatureImportance(model: RandomForestClassificationModel,
featureNames: Array[String]): Unit = {
val importances = model.featureImportances.toArray
val features = featureNames.zip(importances)
.sortBy(-_._2)
.take(20)
println("Top 20 Important Features:")
features.foreach { case (name, importance) =>
println(f"$name: $importance%.4f")
}
}
3. 模型监控
// 模型性能监控
def monitorModelPerformance(model: PipelineModel,
testData: DataFrame): Map[String, Double] = {
val predictions = model.transform(testData)
val metrics = Map(
"accuracy" -> new MulticlassClassificationEvaluator()
.setMetricName("accuracy").evaluate(predictions),
"auc" -> new BinaryClassificationEvaluator()
.setMetricName("areaUnderROC").evaluate(predictions),
"f1" -> new MulticlassClassificationEvaluator()
.setMetricName("f1").evaluate(predictions)
)
// 发送监控指标
sendMetricsToMonitoringSystem(metrics)
metrics
}
总结
MLlib提供了完整的大规模机器学习解决方案:
核心优势:
- 分布式计算:支持大规模数据集的机器学习任务
- 统一API:ML Pipeline提供了一致的编程接口
- 丰富算法:涵盖分类、回归、聚类、推荐等主要任务
- 生产应用基础:提供模型持久化和批量推理接口;在线服务化仍需另行集成部署组件
适用场景:
- 大规模数据集的机器学习
- 特征工程和数据预处理
- 模型训练和调优
- 实时机器学习推理
最佳实践:
- 合理设计特征工程Pipeline
- 使用交叉验证进行模型选择
- 实施模型版本管理和监控
- 优化资源配置和性能参数
相关文档
- DataFrame和Dataset:结构化数据处理基础
- Python机器学习:机器学习算法对比
- Spark性能调优:性能优化策略
- 企业级应用:生产环境部署