仅使用 Spark MLlib 的线性回归 returns 单调预测

Linear regression with Spark MLlib only returns monotonic predictions

检查问题底部的更新

总结:我有一个行为不是线性的数据集。我正在尝试使用 Spark 的 MLlib(v1.5.2) 来拟合一个更像多项式函数的模型,但结果我总是得到一个线性模型。我不知道是否无法使用线性回归获得 non-linear 模型。

[TL;DR] 我正在尝试拟合一个足以代表以下数据的模型:

我的代码非常简单(与每个教程中的代码非常相似)

object LinearRegressionTest {

   def main(args: Array[String]): Unit = {
      val sc = new SparkContext("local[2]", "Linear Regression")
      val data = sc.textFile("data2.csv")
      val parsedData = data.map { line =>
         val parts = line.split(',')
         LabeledPoint(parts(1).toDouble, Vectors.dense(parts(2).toDouble))
       }.cache()

      val numIterations = 1000
      val stepSize = 0.001

      val model = LinearRegressionWithSGD.train(parsedData, numIterations, stepSize)
      sc.stop
   }
}

获得的结果在正确的范围内,但它们始终处于单调递增的直线上。我正在努力思考它,但我无法弄清楚为什么没有拟合出更好的曲线。

有什么建议吗?

谢谢大家

更新 问题是由我们使用的 spark 和 spark-ml 库的版本引起的。出于某种原因,即使我提供了更多功能(输入数据的平方或立方版本),1.5.2 版也没有拟合出更好的曲线。在升级到版本 2.0.0 并从不推荐使用的 LinearRegressionWithSGD 切换到主要 API(不是 RDD API)的 LinearRegression 之后,该算法的行为符合预期。使用这种新方法,模型拟合了正确的曲线。

这里没有什么意外。您使用

形式的线性模型
Y = βx + ε

因此拟合结果将始终形成一条穿过原点的线(与例如 R 不同,默认情况下 Spark 不适合截距)并且只要模型至少稍微正常,它就应该增加以近似分布数据。

虽然 Whosebug 上可能没有详细信息,但您应该从添加更多功能开始。很明显,这里的近似值必须是二次的,所以让我们一步一步地说明这一点。我们将从对您的数据进行非常粗略的估计开始:

y <- c(0.6, 0.6, 0.6, 0.6, 0.575, 0.55, 0.525, 0.475, 0.45, 0.40, 0.35, 0.30)
df <- data.frame(y=c(y, rev(y)), x=0:23)
plot(df$x, df$y)

在 Spark 中创建的模型大致等同于:

lm1 <- lm(y ~ x + 0, df)
lines(df$x, predict(lm1, df), col='red')

由于很明显模型通过原点传递不是一个好的让我们尝试添加一个截距:

lm2 <- lm(y ~ x, df)
lines(df$x, predict(lm2, df), col='blue')

最后我们知道我们需要一些非线性:

df$x2 <- df$x ** 2
lm3 <- lm(y ~ x + x2, df)
lines(df$x, predict(lm3, df), col='green')

这里带走的消息是:

  • 创建模型时使用 setIntercept(true) LinearRegressionModel,
  • 向模型添加一些非线性特征。

    val x = arts(2).toDouble
    LabeledPoint(parts(1).toDouble, Vectors.dense(x, x*x))