Mit logistischer Regression, Scala und Spark

Mit logistischer Regression, Scala und Spark

  • Künstliche Intelligenz
6 Minuten Lesezeit Aktualisiert Jun 9, 2017

Auf einen Blick: Die logistische Regression mit Apache Spark wird demonstriert, um binäre Ergebnisse vorherzusagen, insbesondere auf Brustkrebspatientendaten in Scala. Das Tutorial behandelt Datenvorbereitung, Modelltraining und Bewertung von Variablenbeziehungen.

  • Logistische Regression sagt Wahrscheinlichkeiten für binäre Ergebnisse voraus.
  • Nutzt Daten von Brustkrebspatienten zur Modellierung.

Hier erklären wir, wie man logistische Regression mit Apache Spark durchführt.

Die logistische Regression (LR) steht in engem Zusammenhang mit der linearen Regression.  Aber anstatt einen abhängigen Wert bei unabhängigen Eingabewerten vorherzusagen, sagt sie eine Wahrscheinlichkeit und ein binäres, ja- oder nein-Ergebnis voraus.

Man verwendet lineare oder logistische Regression, wenn man glaubt, dass es eine Beziehung zwischen den Variablen gibt.  Zum Beispiel korreliert die Anzahl der Stunden, die man lernt, offensichtlich mit den Noten.  Man könnte also lineare oder logistische Regression dazu verwenden.

Die logistische Regression ergibt eine 0 (falsch) oder 1 (wahr).  Konventionell gilt: Wenn die Wahrscheinlichkeit eines Ereignisses > 50 % beträgt, weist LR den Wert 1 zu.

Um zu veranschaulichen, wie dies genutzt werden kann, werden wir Daten aus einer Studie mit Brustkrebspatientinnen an der University of Massachusetts in ein einfaches LR-Modell einfügen.

Brustkrebsdaten

Die Beschreibung des Datensatzes finden Sie hier.  Die Daten im Excel-Format finden Sie hier. Und die Daten im Textdateiformat sind hier.

Schauen Sie sich die Beschreibung und die Excel-Datei an.  Dies sind 50 Patienten, bei denen eine Brusterkrankung diagnostiziert wurde, und 150, die keine (die Kontrollgruppe).  Zu den Faktoren gehören Alter, Anzahl der Fehlgeburten usw. Die  Diagnose (1=ja 0=nein) steht in Spalte D mit Spaltenüberschrift FNDX.

Das Gute ist, dass all diese Daten numerisch sind und speziell für ein LR-Modell angelegt sind.  Alles, was wir tun müssen, ist, die erforderlichen Datenstrukturen zu erstellen, um sie in das Spark ML LR-Modell einzuspeisen.

Um zu beginnen, laden Sie die .dat-Datei herunter und bearbeiten sie, um den einleitenden Text und die Spaltenüberschriften zu entfernen.  Wir werden die Leerzeichen mit Code entfernen und auch Zeilen (Patientenakten) mit fehlenden Werten entfernen.  Wir können keine unvollständigen Daten ins Modell einfügen.

Kommentare zu den Daten

Beachten Sie, dass die meisten Leute, die diese Art von Programmierung unterrichten, die Eingabedaten  zunächst in Trainings- und Testdatensätze aufteilen, indem sie sie in zwei Teile aufteilen. Aber das ist nicht  ganz logisch.

Der Zweck der .dat Datei, die wir aus dem Internet heruntergeladen haben, ist es, das Modell zu trainieren. Mit anderen Worten: Sie verwendet kleinste Quadrate oder andere Techniken, um die Linie zu finden, die am nächsten an die Eingabe passt.

Um das statistisch zu fassen, berechnet es die Koeffizienten und Schnittpunkte, um eine Formel wie y = mx + b zu erzeugen, wobei m der Koeffizient, b der Schnittpunkt und y der vorhergesagte Wert ist. Aber hier haben wir viel mehr Eingabevariablen als nur x.

Nachdem wir dieses Modell entwickelt haben, würden wir das verwenden und nur einen Datensatz von einem Patienten eingeben, der in die Arztpraxis gekommen ist. Dann können wir vorhersagen, ob diese Patientin wahrscheinlich Brustkrebs hat. Es gibt bereits Computer in Arztpraxen, die genau das tun.

Unten ist der Scala-Code. Starten Sie Spark-Shell, um den Kommandozeilen-Interpreter zu verwenden, oder verwenden Sie ein Zeppelin-Notizbuch. Wir fügen Kommentare in den Code ein, um das zu erklären.

Scala-Code

Scala-Code

    import org.apache.spark.sql
import org.apache.spark.sql._
import org.apache.spark.sql.types._
import org.apache.spark.ml.classification.LogisticRegression
import org.apache.spark.mllib.linalg.{Vector, Vectors}
import org.apache.spark.ml.evaluation.BinaryClassificationEvaluator
import org.apache.spark.ml.feature.{VectorAssembler, StringIndexer}
/**
*  Missing values show up as a dot.  The dot function below
*  returns -1 if there is a dot or blank value. And it converts strings to double.
* Then later we will
*  delete all rows that have any -1 values.
*/
def dot (s: String) : Double = {
if (s.contains(".") || s.length == 0) {
return -1
} else {
return s.toDouble
}
}
/**
*  We are going to use a Dataframe.  It requires a schema.
* So we create that below.  We use the same column names
*  as are in the .dat file.
*/
val schema = StructType (
StructField("STR", DoubleType, true) ::
StructField("OBS", DoubleType, true) ::
StructField("AGMT", DoubleType, true) ::
StructField("FNDX", DoubleType, true) ::
StructField("HIGD", DoubleType, true) ::
StructField("DEG",DoubleType, true) ::
StructField("CHK", DoubleType, true) ::
StructField("AGP1", DoubleType, true) ::
StructField("AGMN", DoubleType, true) ::
StructField("NLV", DoubleType, true) ::
StructField("LIV", DoubleType, true) ::
StructField("WT", DoubleType, true) ::
StructField("AGLP", DoubleType, true) ::
StructField("MST", DoubleType, true) ::  Nil)
/**
*  Read in the .dat file and use the regular expression
*  \s+ to split it by spaces into an RDD.
*/
val readingsRDD = spark.sparkContext.textFile("/home/walker/bbdm13.dat")
val RDD = readingsRDD.map(_.split("\\s+"))
/**
*   Run the dot function over every element in the RDD to convert them
*   to doubles, since that if the format requires by the Spark ML LR model.
*   Note that we skip the first one since that is just a blank space.
*/
val rowRDD = RDD.map(s => Row(dot(s(1)),dot(s(2)),dot(s(3)),dot(s(4)),dot(s(5)),dot(s(6)),
dot(s(7)),dot(s(8)),dot(s(9)),dot(s(10)),dot(s(11)),dot(s(12)),
dot(s(13)),dot(s(14))))
/**
* Now create a dataframe with the schema we described above,
*
*/
val readingsDF = spark.createDataFrame(rowRDD, schema)
/**
*  Create a new dataframe dropping all of those with missing values.
*/
var cleanDF = readingsDF.filter(readingsDF("STR") > -1 && readingsDF("OBS") > -1 && readingsDF("AGMT")  > -1  && readingsDF("FNDX") > -1 && readingsDF("HIGD") > -1  && readingsDF("DEG") > -1 && readingsDF("CHK") > -1 && readingsDF("AGP1") > -1  && readingsDF("AGMN") > -1  && readingsDF("NLV") > -1  && readingsDF("LIV") > -1 && readingsDF("WT") > -1 && readingsDF("AGLP") > -1 && readingsDF("MST") > -1)
/**
*  Now comes something more complicated.  Our dataframe has the column headings
*  we created with the schema.  But we need a column called “label” and one called
* “features” to plug into the LR algorithm.  So we use the VectorAssembler() to do that.
* Features is a Vector of doubles.  These are all the values like patient age, etc. that
* we extracted above.  The label indicated whether the patient has cancer.
*/
val featureCols = Array("STR" , "OBS" , "AGMT" , "HIGD" , "DEG" , "CHK" , "AGP1" , "AGMN" , "NLV" , "LIV" , "WT" , "AGLP",  "MST" )
val assembler = new VectorAssembler().setInputCols(featureCols).setOutputCol("features")
val df2 = assembler.transform(cleanDF)
/**
* Then we use the StringIndexer to take the column FNDX and make that the label.
*  FNDX is the 1 or 0 indicator that shows whether the patient has cancer.
* Like the VectorAssembler it will add another column to the dataframe.
*/
val labelIndexer = new StringIndexer().setInputCol("FNDX").setOutputCol("label")
val df3 = labelIndexer.fit(df2).transform(df2)
/**
*   Now we declare the LR model and run fit and transform to make predictions.
*/
val model = new LogisticRegression().fit(df3)
val predictions = model.transform(df3)
/**
*  Now we print it out.  Notice that the LR algorithm added a “prediction” column
*  to our dataframe.   The prediction in almost all cases will be the same as the label.  That is
* to be expected it there is a strong correlation between these values.  In other words
* if the chance of getting cancer was not closely related to these variables then LR
* was the wrong model to use.  The way to check that is to check the accuracy of the model.
*  You could use the BinaryClassificationEvaluator Spark ML function to do that.
* Adding that would be a good exercise for you, the reader.
*/
predictions.select ("features", "label", "prediction").show()
+--------------------+-----+----------+
|            features|label|prediction|
+--------------------+-----+----------+
|[1.0,1.0,39.0,9.0...|  1.0|        1.0|
|[1.0,2.0,39.0,10....|  0.0|        0.0|
|[1.0,3.0,39.0,11....|  0.0|        0.0|
|[1.0,4.0,39.0,12....|  0.0|        0.0|
|[2.0,2.0,38.0,12....|  0.0|        0.0|
|[2.0,3.0,38.0,9.0...|  0.0|        0.0|
|[2.0,4.0,38.0,13....|  0.0|        0.0|
|[3.0,1.0,38.0,9.0...|  1.0|        1.0|
|[3.0,2.0,38.0,10....|  0.0|        0.0|
|[3.0,3.0,38.0,15....|  0.0|        0.0|
|[3.0,4.0,38.0,12....|  0.0|        0.0|
|[4.0,1.0,38.0,15....|  1.0|        1.0|
|[4.0,2.0,38.0,15....|  0.0|        0.0|
|[4.0,3.0,38.0,12....|  0.0|        0.0|
|[4.0,4.0,38.0,12....|  0.0|        0.0|
|[5.0,1.0,38.0,12....|  1.0|        1.0|
|[5.0,2.0,38.0,12....|  0.0|        0.0|
|[5.0,4.0,38.0,13....|  0.0|        0.0|
|[6.0,1.0,38.0,13....|  1.0|        1.0|
|[6.0,2.0,38.0,12....|  0.0|        0.0|
+--------------------+-----+----------+
only showing top 20 rows

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.