Spark决策树分类器运行问题:标签为Double类型且取值-20至+20
关于Spark DecisionTreeClassifier处理Double类型标签的解决方案
嘿,我看你在尝试用Spark的DecisionTreeClassifier,但你的标签字段是Double类型,取值在-20到+20之间——这里得先提个关键问题:Spark的分类器(包括决策树分类器)是用来预测离散类别的,它要求标签得是整数类型的类别值(比如0、1、2这类),而不是连续的Double数值。下面分两种场景给你解决方案:
场景1:你的任务其实是回归(预测连续数值)
如果你的目标是预测-20到20之间的连续值,那你不该用分类器,应该用DecisionTreeRegressor(决策树回归器),它专门处理连续输出的任务。示例代码如下:
import org.apache.spark.ml.regression.DecisionTreeRegressor import org.apache.spark.ml.regression.DecisionTreeRegressionModel import org.apache.spark.ml.evaluation.RegressionEvaluator import java.io.File val dtModelPath = s"file:///home/parv/spark/examples/src/main/scala/org/apache/spark/examples/ml/dtModel" // 初始化回归器 val dtRegressor = new DecisionTreeRegressor() .setLabelCol("yourLabelCol") // 直接用你原来的Double类型标签列 .setFeaturesCol("yourFeaturesCol") // 替换为你的特征列名 // 训练并保存模型 val dtRegModel = dtRegressor.fit(yourTrainingData) dtRegModel.save(dtModelPath) // 评估模型 val predictions = dtRegModel.transform(yourTestData) val evaluator = new RegressionEvaluator() .setLabelCol("yourLabelCol") .setPredictionCol("prediction") .setMetricName("rmse") // 用均方根误差评估 val rmse = evaluator.evaluate(predictions) println(s"Test RMSE = $rmse")
场景2:你确实需要做分类任务
如果你的目标是把标签分成离散类别,那得先把连续的Double标签转换成整数类型的类别值。这里给你两种转换方式:
方式1:二分类(将标签分成两类)
比如设定一个阈值(比如0),把大于0的标记为1,小于等于0的标记为0:
import org.apache.spark.sql.functions.{when, col} import org.apache.spark.ml.classification.DecisionTreeClassifier import org.apache.spark.ml.evaluation.BinaryClassificationEvaluator // 转换标签为二分类格式 val binaryLabeledData = yourOriginalData.withColumn( "label", when(col("yourLabelCol") > 0, 1.0).otherwise(0.0) // Spark二分类接受Double类型的0.0/1.0 ) // 初始化决策树分类器 val dtClassifier = new DecisionTreeClassifier() .setLabelCol("label") .setFeaturesCol("yourFeaturesCol") // 训练模型 val dtModel = dtClassifier.fit(binaryLabeledData) // 保存模型(复用你原来的路径) val dtModelPath = s"file:///home/parv/spark/examples/src/main/scala/org/apache/spark/examples/ml/dtModel" dtModel.save(dtModelPath) // 评估二分类模型 val predictions = dtModel.transform(binaryLabeledData) val evaluator = new BinaryClassificationEvaluator() .setLabelCol("label") .setPredictionCol("prediction") .setMetricName("areaUnderROC") val auc = evaluator.evaluate(predictions) println(s"Test AUC = $auc")
方式2:多分类(将标签分成多个区间类别)
用Bucketizer把-20到20的范围分成多个区间,每个区间对应一个整数类别:
import org.apache.spark.ml.feature.Bucketizer import org.apache.spark.ml.classification.DecisionTreeClassifier import org.apache.spark.ml.evaluation.MulticlassClassificationEvaluator // 定义分桶边界,比如分成4个区间:[-20,-10), [-10,0), [0,10), [10,20] val splits = Array(-20.0, -10.0, 0.0, 10.0, 20.0) val bucketizer = new Bucketizer() .setInputCol("yourLabelCol") .setOutputCol("label") // 转换后的标签列,对应0、1、2、3四个类别 .setSplits(splits) // 转换数据集 val multiLabeledData = bucketizer.transform(yourOriginalData) // 训练多分类决策树 val dtClassifier = new DecisionTreeClassifier() .setLabelCol("label") .setFeaturesCol("yourFeaturesCol") .setMaxDepth(5) // 可根据需求调整树深度 val dtModel = dtClassifier.fit(multiLabeledData) // 保存模型 val dtModelPath = s"file:///home/parv/spark/examples/src/main/scala/org/apache/spark/examples/ml/dtModel" dtModel.save(dtModelPath) // 评估多分类模型 val predictions = dtModel.transform(multiLabeledData) val evaluator = new MulticlassClassificationEvaluator() .setLabelCol("label") .setPredictionCol("prediction") .setMetricName("accuracy") val accuracy = evaluator.evaluate(predictions) println(s"Test Accuracy = $accuracy")
最后提醒一下:不管哪种场景,都要确保你的特征列已经做了必要的预处理(比如转换成Vector类型),不然模型会报错哦~
内容的提问来源于stack exchange,提问作者Parv bali
相关产品推荐
相关产品推荐

