|
|
@@ -0,0 +1,114 @@
|
|
|
+package com.example.model.classification
|
|
|
+import java.util
|
|
|
+import com.example.SparkConnect
|
|
|
+import com.example.entity.Model
|
|
|
+import com.example.model.helper.Utils
|
|
|
+import org.apache.spark.ml.classification.{DecisionTreeClassificationModel, DecisionTreeClassifier, LogisticRegression, LogisticRegressionModel}
|
|
|
+import org.apache.spark.ml.evaluation.MulticlassClassificationEvaluator
|
|
|
+import org.apache.spark.ml.feature.{IndexToString, StringIndexer, VectorIndexer}
|
|
|
+import org.apache.spark.ml.{Pipeline, PipelineModel, PipelineStage}
|
|
|
+import org.apache.spark.sql.{Dataset, Row}
|
|
|
+import org.springframework.beans.factory.annotation.Autowired
|
|
|
+import org.springframework.stereotype.Component
|
|
|
+import com.example.util.Constant
|
|
|
+
|
|
|
+import scala.collection.mutable
|
|
|
+
|
|
|
+/**
|
|
|
+ * 分类方法的默认实现
|
|
|
+ * @author fanyanpeng
|
|
|
+ * @date 2023/3/22 16:15
|
|
|
+ */
|
|
|
+class DefaultClassification extends SparkConnect {
|
|
|
+
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ val utils: Utils = null
|
|
|
+
|
|
|
+ @throws(classOf[Exception])
|
|
|
+ def training(libsvmFileUri: String,
|
|
|
+ params: util.Map[String,Object]): (PipelineModel,util.Map[String, String]) = {
|
|
|
+
|
|
|
+ val trainSet = sparkSession.read.format("libsvm").load(libsvmFileUri)
|
|
|
+ trainSet.show()
|
|
|
+
|
|
|
+ val maxCategories = params.get(Constant.TRAIN_PARAM_MAX_CATEGORY).asInstanceOf[Int]
|
|
|
+ val featureIndexer = new VectorIndexer()
|
|
|
+ .setInputCol("features")
|
|
|
+ .setOutputCol("indexedFeatures")
|
|
|
+ .setMaxCategories(maxCategories)
|
|
|
+ .fit(trainSet)
|
|
|
+
|
|
|
+ trainSet.show()
|
|
|
+
|
|
|
+ // Split the data into training and test sets (30% held out for testing).
|
|
|
+ //为了对训练效果进行评估,将训练集进一步划分为子训练集与子测试集
|
|
|
+ var Array(subTrainSet:Dataset[Row], subTestSet:Dataset[Row]) = trainSet.randomSplit(Array(0.7, 1 - 0.7))
|
|
|
+
|
|
|
+ /*******************************************/
|
|
|
+ //需要由子类实现
|
|
|
+ val classifier = buildClassifier(params)
|
|
|
+ /*******************************************/
|
|
|
+
|
|
|
+ val pipeline = new Pipeline()
|
|
|
+ .setStages(Array(featureIndexer, classifier))
|
|
|
+
|
|
|
+ // Train model. This also runs the indexers.
|
|
|
+ val pipelineModel:PipelineModel = pipeline.fit(subTrainSet)
|
|
|
+
|
|
|
+
|
|
|
+ val resultMap:util.Map[String,String] = new util.HashMap[String,String]()
|
|
|
+ // Make predictions.
|
|
|
+ val predictions = pipelineModel.transform(subTestSet)
|
|
|
+
|
|
|
+ // Select (prediction, true label) and compute test error.
|
|
|
+ //为了简便,使用了多分类
|
|
|
+ val evaluator = new MulticlassClassificationEvaluator()
|
|
|
+ .setLabelCol("label")
|
|
|
+ .setPredictionCol("prediction")
|
|
|
+
|
|
|
+
|
|
|
+ val weightedRecall = evaluator.setMetricName("weightedRecall").evaluate(predictions);
|
|
|
+ val accuracy = evaluator.setMetricName("accuracy").evaluate(predictions)
|
|
|
+ log.info("Test Error = " + (1.0 - accuracy))
|
|
|
+ val weightedPrecision = evaluator.setMetricName("weightedPrecision").evaluate(predictions);
|
|
|
+ val f1 = evaluator.setMetricName("f1").evaluate(predictions);
|
|
|
+
|
|
|
+
|
|
|
+ val model = pipelineModel.stages(1).asInstanceOf[LogisticRegressionModel]
|
|
|
+ //println("Learned classification tree model:\n" + treeModel.toDebugString)
|
|
|
+ log.info("\n\nLearned classification Logistic model:\n" + model.toString());
|
|
|
+
|
|
|
+
|
|
|
+ resultMap.put("Accuracy: ", accuracy.toString)
|
|
|
+ resultMap.put("weightedPrecision", weightedPrecision.toString)
|
|
|
+ resultMap.put("weightedRecall", weightedRecall.toString)
|
|
|
+ resultMap.put("f1", f1.toString)
|
|
|
+
|
|
|
+ return (pipelineModel, resultMap)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 默认实现:逻辑回归
|
|
|
+ * @author fanyanpeng
|
|
|
+ * @date 2023/3/22 16:44
|
|
|
+ * @param params 参数列表
|
|
|
+ * @return org.apache.spark.ml.PipelineStage
|
|
|
+ */
|
|
|
+ def buildClassifier(params:util.Map[String,Object]):PipelineStage = {
|
|
|
+ val maxIter = params.get(Constant.TRAIN_PARAM_MAX_ITER).asInstanceOf[Int]
|
|
|
+ val regParam = params.get(Constant.TRAIN_PARAM_REG_PARAM).asInstanceOf[Float]
|
|
|
+ val elasticNetParam = params.get(Constant.TRAIN_PARAM_ELASTICNET_PARAM).asInstanceOf[Float]
|
|
|
+
|
|
|
+ val lr = new LogisticRegression()
|
|
|
+ .setLabelCol("label")
|
|
|
+ .setFeaturesCol("indexedFeatures")
|
|
|
+ .setMaxIter(maxIter)
|
|
|
+ .setRegParam(regParam)
|
|
|
+ .setElasticNetParam(elasticNetParam)
|
|
|
+ lr
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|