【问题标题】:Spark MLLib Linear Regression model intercept is always 0.0?Spark MLLib线性回归模型截距总是0.0?
【发布时间】:2014-12-03 06:44:57
【问题描述】:

我刚开始使用 ML 和 Apache Spark,所以我一直在尝试基于 Spark 示例的线性回归。除了示例中的样本,我似乎无法为任何数据生成合适的模型,并且无论输入数据如何,截距始终为 0.0。

我已经准备了一个基于函数的简单训练数据集:

y = (2*x1) + (3*x2) + 4

即我希望截距为 4,权重为 (2, 3)。

如果我对原始数据运行 LinearRegressionWithSGD.train(...),则模型为:

Model intercept: 0.0, weights: [NaN,NaN]

而且预测都是NaN:

Features: [1.0,1.0], Predicted: NaN, Actual: 9.0
Features: [1.0,2.0], Predicted: NaN, Actual: 12.0

如果我先缩放数据,我会得到:

Model intercept: 0.0, weights: [17.407863391511754,2.463212481736855]

Features: [1.0,1.0], Predicted: 19.871075873248607, Actual: 9.0
Features: [1.0,2.0], Predicted: 22.334288354985464, Actual: 12.0
Features: [1.0,3.0], Predicted: 24.797500836722318, Actual: 15.0

要么我做错了,要么我不明白这个模型的输出应该是什么,所以任何人都可以建议我在这里可能出错的地方吗?

我的代码如下:

   // Load and parse the dummy data (y, x1, x2) for y = (2*x1) + (3*x2) + 4
   // i.e. intercept should be 4, weights (2, 3)?
   val data = sc.textFile("data/dummydata.txt")

   // LabeledPoint is (label, [features])
   val parsedData = data.map { line =>
    val parts = line.split(',')
    val label = parts(0).toDouble
    val features = Array(parts(1), parts(2)) map (_.toDouble)
    LabeledPoint(label, Vectors.dense(features))
  }

  // Scale the features
  val scaler = new StandardScaler(withMean = true, withStd = true)
                   .fit(parsedData.map(x => x.features))
  val scaledData = parsedData
                  .map(x => 
                  LabeledPoint(x.label, 
                     scaler.transform(Vectors.dense(x.features.toArray))))

  // Building the model: SGD = stochastic gradient descent
  val numIterations = 1000
  val step = 0.2
  val model = LinearRegressionWithSGD.train(scaledData, numIterations, step)

  println(s">>>> Model intercept: ${model.intercept}, weights: ${model.weights}")`

  // Evaluate model on training examples
  val valuesAndPreds = scaledData.map { point =>
    val prediction = model.predict(point.features)
    (point.label, point.features, prediction)
  }
  // Print out features, actual and predicted values...
  valuesAndPreds.take(10).foreach({case (v, f, p) => 
      println(s"Features: ${f}, Predicted: ${p}, Actual: ${v}")})

【问题讨论】:

  • 对于 PySpark,如果有人想知道,这将是 model = LinearRegressionWithSGD.train(res, intercept = True)

标签: scala apache-spark apache-spark-mllib


【解决方案1】:

您正在使用的train 方法是一种快捷方式,可将截距设置为零并且不尝试找到截距。如果您使用底层类,您可以获得非零截距:

val model = new LinearRegressionWithSGD(step, numIterations, 1.0).
    setIntercept(true).
    run(scaledData)

现在应该给你一个拦截。

【讨论】:

  • 感谢您将我指向构造函数,Noah。它似乎不接受任何参数(在 Spark 1.1 中),但这没关系,因为该模型现在使用内置默认值产生了非常好的结果。干杯!
  • @ChrisWebster 看起来构造函数被标记为私有,不知道为什么。我在火花源中进行测试,所以它在范围内工作。无论如何,一个简单的解决方法是添加一个只有 1 的列作为你的截距,因为这就是线性回归代码在幕后所做的。
【解决方案2】:

@Noah:谢谢 - 您的建议促使我再次查看此内容,我发现 some example code here 允许您通过优化器生成截距并设置其他参数,例如迭代次数。

这是我修改后的模型生成代码,在我的虚拟数据上似乎可以正常工作:

  // Building the model: SGD = stochastic gradient descent:
  // Need to setIntercept = true, and seems only to work with scaled data 
  val numIterations = 600
  val stepSize = 0.1
  val algorithm = new LinearRegressionWithSGD()
  algorithm.setIntercept(true)
  algorithm.optimizer
    .setNumIterations(numIterations)
    .setStepSize(stepSize)

  val model = algorithm.run(scaledData)

它似乎仍然需要缩放数据,而不是原始数据,作为输入,但这对于我的目的来说是可以的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-31
    • 2017-10-29
    • 2016-12-12
    • 2014-07-19
    • 2022-01-09
    • 1970-01-01
    • 2019-05-27
    • 1970-01-01
    相关资源
    最近更新 更多