Я только начинаю работать с ML и Apache Spark, поэтому пробовал опробовать линейную регрессию на основе примеров Spark. Кажется, я не могу создать подходящую модель для каких-либо данных, кроме образца в примере, а перехват всегда равен 0,0, независимо от входных данных.

Я подготовил простой набор обучающих данных на основе функции:

У = (2 * х1) + (3 * х2) + 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}")})
8
Chris Webster 8 Окт 2014 в 18:42
Для PySpark, если кому интересно, это будет model = LinearRegressionWithSGD.train(res, intercept = True)
 – 
David Arenburg
18 Авг 2016 в 13:22

2 ответа

Лучший ответ

Используемый вами метод train - это ярлык, который устанавливает точку пересечения в ноль и не пытается ее найти. Если вы используете базовый класс, вы можете получить ненулевой перехват:

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

Должен дать вам перехват сейчас.

9
Noah 8 Окт 2014 в 19:03
Спасибо, что указали мне на конструктор, Ной. Кажется, что он не принимает никаких аргументов (в Spark 1.1), но это нормально, так как модель в любом случае дает довольно хорошие результаты со встроенными значениями по умолчанию. Ваше здоровье!
 – 
Chris Webster
8 Окт 2014 в 19:25
1
Похоже, что конструктор помечен как частный, не знаю почему. Я тестировал в источнике искры, поэтому он работал в объеме. В любом случае, простой обходной путь заключается в том, чтобы добавить столбец всего из 1 для использования в качестве вашего перехвата, поскольку код линейной регрессии в любом случае делает это за кулисами.
 – 
Noah
8 Окт 2014 в 19:31

@Noah: Спасибо - ваш совет побудил меня взглянуть на это еще раз, и я нашел здесь есть пример кода, который позволяет вам сгенерировать перехват, а также установить другие параметры, такие как количество итераций, через оптимизатор.

Вот мой исправленный код генерации модели, который, кажется, работает с моими фиктивными данными:

  // 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)

Кажется, что в качестве входных данных по-прежнему требуются масштабированные данные, а не необработанные данные, но для моих целей это нормально.

11
Chris Webster 9 Окт 2014 в 13:52