SGD-Beispiel für lineare Regression mit Apache Spark

SGD-Beispiel für lineare Regression mit Apache Spark

  • Künstliche Intelligenz
6 Minuten Lesezeit Aktualisiert May 23, 2017

Auf einen Blick: Lineare Regression mit Stochastic Gradient Descent (SGD) mit Apache Spark ermöglicht eine effiziente prädiktive Modellierung. Dieses Tutorial bietet einen umfassenden Leitfaden zur Implementierung des Modells in Scala, der Datenverarbeitung, Training und Fehlerberechnung abdeckt.

  • SGD ist auf spezifische Analyseherausforderungen zugeschnitten.

  • Der mittlere quadratische Fehler (MSE) wird zur Bewertung der Modellgenauigkeit verwendet.

  • Erfahren Sie mehr über die Machine Learning Pipeline von Apache Spark.

Dieser Artikel erklärt, wie man lineare Regression mit Apache Spark durchführt. Er setzt voraus, dass du grundlegende Kenntnisse der linearen Regression hast. Wenn nicht, musst du dich damit beschäftigen, da es eine der einfachsten Ideen in der Statistik ist. Außerdem sind die meisten Maschinensprachmodelle eine Erweiterung dieser Grundidee. Es ist so einfach zu verstehen und zu verwenden, dass du es mit Google Sheets oder Microsoft Excel machen kannst. Obwohl du in diesen Tools auf eine Eingabevariable beschränkt bist. Unser Beispiel hier hat etwa 12. Das Ziel ist es, eine Formel zu entwickeln, um ein prädiktives Modell zu erstellen. Ab der Highschool wirst du das Modell hier als die Formel für eine gerade Linie erkennen, wobei b der Punkt ist, an dem die Linie die y-Achse kreuzt.

    y = mx + b

Zum Beispiel könnten wir annehmen, dass Umsatz- und Werbeausgaben miteinander zusammenhängen. Wir könnten also schreiben:

    y = mx + b
= sales = some function of (advertising expenses ) + constant_value (b)
= (number of ads purchased (m))* (average age cost of ad ( x)) + b.

In diesem Fall ist der Wert für b 0, da keine Anzeigen keine Ausgaben bedeuten. Die klassische Lösung dieses Problems ist, die Linie zu finden.

    y = mx + b

das diese Daten fast genau in der Mitte aufteilt, wie im untenstehenden Diagramm gezeigt. Dazu finden wir die Linie, deren durchschnittlicher Abstand zu den Datenpunkten am kleinsten ist.

Der einfachste Weg, diese Linie in Apache Spark zu finden, ist, Folgendes zu verwenden:

    org.apache.spark.mllib.regression.LinearRegressionMode.

Ein ausgefeilterer Ansatz ist jedoch, Folgendes zu verwenden:

    org.apache.spark.mllib.regression.LinearRegressionWithSGD

wobei stochastischer Gradientenabstieg steht. Aus Gründen, die über den Rahmen dieses Dokuments hinausgehen, genügt es zu sagen, dass SGD für bestimmte analytische Probleme besser geeignet ist als andere. Welcher Algorithmus am besten geeignet ist, basiert auf vielen Faktoren – wie zum Beispiel, welcher die besten Schätzungen macht, die Effizienz des Algorithmus, die Tendenz, einen Algorithmus zu übertrainieren (was zu Schlüssen führt, die durch vorurteilsbehaftete Annahmen verzerrt sind), seiner Empfindlichkeit gegenüber Ausreißern (das heißt, er vermischt die Schätzung, wenn Datenpunkte weit von den anderen entfernt sind) usw. Die einzige Möglichkeit zu wissen, welches Modell verwendet werden sollte, ist, das Modell mit dem geringsten Fehler zu finden, also das Modell, das den kleinsten Unterschied zwischen den vorhergesagten und beobachteten Werten liefert. Das ist es, was Data Scientists tun – sie probieren mehrere Modelle aus.

Wie man lineare Regression mit Apache Spark und Scala programmiert

Laden Sie diese Daten herunter: https://raw.githubusercontent.com/cloudera/spark/master/mllib/data/ridge-data/lpsa.data Es spielt keine Rolle, was diese Daten sind. Wir interessieren uns nicht für die Spaltenüberschriften oder überhaupt dafür, was diese Daten bedeuten. Wir wollen nur zeigen, wie man lineare Regressionen macht, und brauchen Daten, die korrelieren. Viele Daten korrelieren überhaupt nicht, das heißt, lineare Regression oder irgendeine Art von Statistik passt nicht dazu. Zum Beispiel sind Benzinpreise und Benzinverkäufe kaum korreliert, da Menschen Gas unabhängig vom Preis kaufen, weil sie es brauchen. Zuerst zeigen wir den gesamten Code, dann gehen wir ihn Zeile für Zeile durch.

    import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.mllib.feature.Normalizer
import org.apache.spark.mllib.regression.LinearRegressionWithSGD
val data = sc.textFile("/home/walker/lpsa.dat")

val parsedData = data.map { line =>

val x : Array[String] = line.replace(",", " ").split(" ")

val y = x.map{ (a => a.toDouble)}

val c = Vectors.dense(y(0),y(d))

LabeledPoint(y(0), c)

val stepSize = 0.00000001

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

val valuesAndPreds = parsedData.map { point =>

val prediction = model.predict(point.features)

(point.label, prediction)

val MSE = valuesAndPreds.map{ case(v, p) => math.pow((v - p), 2) }.mean()

val parsedData = data.map { line =>
val x : Array[String] = line.replace(",", " ").split(" ")
val y = x.map{ (a => a.toDouble)}
val parsedData = data.map { line =>
val x : Array[String] = line.replace(",", " ").split(" ")
val y = x.map{ (a => a.toDouble)}
val d = y.size - 1
val c = Vectors.dense(y(0),y(d))
LabeledPoint(y(0), c)
}.cache()

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

val valuesAndPreds = parsedData.map { point =>
val prediction = model.predict(point.features)
(point.label, prediction)
}
    -0.4307829,-1.63735562648104 -2.00621178480549 -1.86242597251066 -1.02470580167082 -0.522940888712441 -0.863171185425945 -1.04215728919298 -0.864466507337306

Das erzeugt Daten als RDD[String].

    val data = sc.textFile("/home/walker/lpsa.dat")

Eine Zeichenkette ist ein iterables Objekt, daher schleifen wir zweimal darüber, um sie in Leerzeichen zu unterteilen. Wir machen das zweimal, weil man in den Daten sehen kann, dass die ersten beiden Elemente durch ein Komma getrennt sind, also müssen wir das zuerst entfernen.

    val parsedData = data.map { line =>
val x : Array[String] = line.replace(",", " ").split(" ")

Wir wandeln dann alle diese Strings in Doubles um, da maschinelles Lernen Zahlen benötigt und dieser spezielle Algorithmus einen Vektor von Doubles benötigt.

    val y = x.map{ (a => a.toDouble)}

Der LabeledPoint ist ein Objekt, das vom linearen Regressionsalgorithmus benötigt wird. Es ist in diesem Format vorliegend

    (labels, features)

Wobei Features ein Vektor ist. Hier verwenden wir einen dichten Vektor, der ein Typ ist, der keine leeren Werte verarbeitet, von denen wir keine haben.

    val parsedData = data.map { line =>
val x : Array[String] = line.replace(",", " ").split(" ")
val y = x.map{ (a => a.toDouble)}
val d = y.size - 1
val c = Vectors.dense(y(0),y(d))
LabeledPoint(y(0), c)
}.cache()

Beachten Sie, dass wir das Wort Cache verwenden, weil Spark ein verteiltes System ist. Um dies zu berechnen, müssen wir Daten von jedem Knoten abrufen. Cache, wie Collect, sammelt alle Elemente über die Knoten hinweg.

Training mit Testdaten

In diesem Beispiel verwenden wir auch das Trainingsset als Testdaten . Das ist für die Illustration in Ordnung, da beide nahezu gleich sein sollten, wenn sie echte Stichproben tatsächlicher Daten darstellen. Im echten Leben trainiert man auf den Trainingsdaten, zum Beispiel auf der lpsa.dat-Datei. Dann macht man Vorhersagen auf neue eingehende Daten, die Testdaten genannt werden, obwohl ein besserer Name Live-Daten wäre. Es gibt zwei Parameter: Numiterationen und Schrittgröße, zusätzlich zum LabeledPoint. Man müsste die Logik und Mathematik des stochastischen Gradientenabstiegs verstehen, um zu verstehen, was diese bedeuten, was wir hier nicht erklären, da es komplex ist. Im Grunde bedeutet das, wie oft der Algorithmus immer wieder in Schleifen laufen kann, um seine Schätzung anzupassen, also sich auf den Punkt zu konzentrieren, an dem der Fehler so nah wie möglich an null geht. Das nennt man Konvergieren.

    val numIterations = 100
val stepSize = 0.00000001

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

Teste das Modell

Um nun zu sehen, wie gut es funktioniert, schleifen Sie den LabelPoint durch und führen Sie dann die predict()-Methode über jede Methode durch, wodurch ein neues RDD(double, double) aus dem Label (y oder der unabhängigen Variable, also dem beobachteten Endergebnis y) und der Prognose (die Schätzung basierend auf der Regressionsformel des SDG-Algorithmus) erstellt wird.

    val valuesAndPreds = parsedData.map { point =>
val prediction = model.predict(point.features)
(point.label, prediction)
}

Fehler berechnen

Ein Fehler von 0 würde bedeuten, dass wir ein perfektes Modell haben. Wie Sie unten sehen können, sagt das Modell Werte erst gut vorher, wenn das Label hoch ist. Für das gesamte Modell lautet der Fehler:

    println("training Mean Squared Error = " + MSE)
training Mean Squared Error = 7.451030996001437

MSE bedeutet die Differenz zwischen dem Durchschnitt ((vorhergesagter Wert – tatsächlicher Wert ) ** 2 (quadriert)). Wenn der Prädiktiv nahezu dem tatsächlichen Wert ist, liegt MSE nahe bei 0.

    valuesAndPreds.foreach((result) => println(s"predicted label: ${result._1}, actual label: ${result._2}"))
predicted label: -0.4307829, actual label: -6.538896995115336E-8
...
predicted label: 1.446919, actual label: 1.7344923653317994E-7
...
predicted label: 2.6567569, actual label: 3.4906394367410936E-7
predicted label: 1.8484548, actual label: 2.592863859023973E-7
....
predicted label: 2.2975726, actual label: 3.16412860478681E-7
predicted label: 2.7180005, actual label: 3.4164515319254127E-7
predicted label: 2.7942279, actual label: 3.448229999917885E-7
predicted label: 2.8063861, actual label: 3.5506022919177794E-7
predicted label: 2.8124102, actual label: 3.64517218758205E-7
predicted label: 2.8419982, actual label: 3.508992428582512E-7
...
predicted label: 4.029806, actual label: 5.019849314865162E-7
predicted label: 4.1295508, actual label: 5.211902354094908E-7
predicted label: 4.3851468, actual label: 5.732554699437345E-7
predicted label: 4.6844434, actual label: 6.026343831319147E-7
predicted label: 5.477509, actual label: 7.208914981741786E-7

Diese Beiträge sind meine eigenen und spiegeln nicht unbedingt die Position, Strategien oder Meinung von BMC wider.

Mehr aus Künstliche Intelligenz

Interessieren Sie sich für mehr von BMC?

The Brief ist unsere monatliche E-Mail zum Mainframe und zur Enterprise-Orchestrierung: Recherchen, Kundenberichte, Produktnachrichten, Events.

Mit der Registrierung für dieses Angebot bestätigen Sie, dass Sie die Datenschutzrichtlinie von BMC gelesen und zugestimmt haben.

Sie haben The Brief abonniert

Das Briefing umfasst die Mainframe- und Enterprise-Orchestrierung – BMC AMI und Control-M – sowie die Analystenforschung, Kundeneinsätze und Events in beiden Bereichen.