Spark MLlib的线性回归仅返回单调预测

时间:2016-08-05 14:50:47

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

检查问题底部的更新

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

[TL; DR]我试图拟合一个代表足够好以下数据的模型:

enter image description here

我的代码非常简单(非常类似于每个教程)

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并从主API(不是RDD API)的已弃用LinearRegressionWithSGD切换到LinearRegression后,算法按预期运行。使用这种新方法,模型拟合了正确的曲线。

1 个答案:

答案 0 :(得分:4)

这里没有任何意外。您使用形式的线性模型

Y = βx + ε

所以拟合结果将总是形成一条穿过原点的线(与例如R不同,Spark默认不适合截距)并且只要模型至少略微合理,它应该增加以近似分布数据。

虽然StackOverflow上的细节可能不合适,但您应该首先添加更多功能。显而易见的是,这里的体面近似必须是二次的,所以让我们逐步说明。我们将以非常粗略的数据近似开始:

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)

enter image description here

在Spark中创建的模型或多或少等同于:

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

enter image description here

由于很明显通过低谷的模型不是很好,我们试着添加一个拦截:

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

enter image description here

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

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

enter image description here

此处带走的信息是:

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

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