-Einführung in das maschinelle Lernen mit ** Java ** und ** Apache Spark **
Letztes Mal wurde aus CSV-Daten als Spark-Tabellendaten gelesen.
Schauen wir uns nun die Daten an, die dieses Mal zum Lernen verwendet wurden.
Die Daten finden Sie hier [https://raw.githubusercontent.com/riversun/spark-gradient-boosting-tree-regression-example/master/dataset/gem_price_ja.csv].
Dies sind die Daten.
gem_price_ja.csv
id,material,shape,weight,brand,shop,price
0,Silber,Armband,56,Berühmte Marken aus Übersee,Kaufhaus,40864
1,Gold,Ring,48,Inländische berühmte Marke,Direkt verwalteter Laden,63055
2,Dia,Ohrringe,37,Inländische berühmte Marke,Direkt verwalteter Laden,112159
3,Dia,Halskette,20,Berühmte Marken aus Übersee,Direkt verwalteter Laden,216053
4,Dia,Halskette,33,Berühmte Marken aus Übersee,Kaufhaus,219666
5,Silber,Brosche,55,Inländische berühmte Marke,Kaufhaus,16482
6,Platin,Brosche,58,Übersee super berühmte Marke,Direkt verwalteter Laden,377919
7,Gold,Ohrringe,49,Inländische berühmte Marke,Direkt verwalteter Laden,60484
8,Silber,Halskette,59,Keine Marke,Billiger Laden,6256
・ ・ ・ ・
Übrigens, wenn Sie sich ansehen, welche Werte für jeden Variablennamen (Material, Form usw.) verfügbar sind, können Sie sie wie folgt organisieren.
Auf diese Weise sind die Daten auf der linken Seite (** Material, Marke, Geschäft, Form **) der Wert der Zeichenfolge, die die Kategorie angibt. Solche Daten, die nicht direkt als numerischer Wert gemessen werden können, werden als ** qualitative Daten ** bezeichnet.
Andererseits sind die Daten auf der rechten Seite (** Gewicht, Preis **) ein numerischer Wert, der kontinuierliche Werte annimmt. Daten, die direkt als numerischer Wert gemessen oder nach den vier Regeln berechnet werden können, werden als ** quantitative Daten ** bezeichnet.
Wie oben erwähnt, werden Variablen wie ** Material, Marke, Geschäft, Form **, die ** qualitative Daten ** enthalten, als ** kategoriale Variablen ** bezeichnet.
Außerdem werden ** quantitative Daten **, dh Variablen wie ** Gewicht und Preis **, die aufeinanderfolgende Werte (kontinuierliche Werte) annehmen, als ** kategoriale Variablen ** bezeichnet.
Da maschinelles Lernen schließlich eine numerische Berechnung ist, müssen die qualitativen Daten kategorialer Variablen vor der Verarbeitung in einen numerischen Wert umgewandelt werden.
Schauen wir uns die kategorialen Variablen genauer an.
Die kategorialen Variablen ** Material ** und ** Form ** sind das Material des Zubehörs und die Form nach der Verarbeitung (** Form **), aber es gibt einen semantischen Unterschied zwischen ihnen.
** Material ** sind *** Diamant, Platin, Gold, Silber ***, aber wir wissen aus Erfahrung, dass Diamanten teurer sind als Silber, also hat ** Material ** Es scheint eine Hierarchie in den Daten zu geben.
Auf der anderen Seite ist ** Form ** Ringe, Halsketten, Ohrringe, Broschen, Armbänder ***, aber es gibt keine Reihenfolge, in der Armbänder Ringen überlegen sind, und alle Optionen sind gleichberechtigt. Sieht aus als ob.
Diejenigen, in denen die Werte kategorialer Variablen geordnet sind und deren Größe verglichen werden kann, werden als ** Ordnungsvariablen ** (oder Ordnungsskalenvariablen) bezeichnet. [^ 1]
[^ 1]: In diesem Beispiel sind Gold und Platin mit dem gleichen Gewicht derzeit teurer, sodass möglicherweise nicht klar ist, welches das obere ist, aber in einem leicht verständlichen Beispiel ** oben, Mitte, unten * Variablen mit * oder ** hoch, mittel, niedrig ** usw. können eindeutig als Ordnungsvariablen definiert werden.
Wenn andererseits die Werte von kategorialen Variablen nicht eingestuft werden, werden sie als ** nominelle Variable ** (oder nominale Skalenvariable) bezeichnet.
Dies ist der Inhalt, der am Anfang des Statistiklehrbuchs erscheint. Es ist jedoch wichtig, sich daran zu erinnern, da dies ein wichtiges Wissen für die Weiterentwicklung des maschinellen Lernens ist.
Wenn Sie sich diesmal die Daten ansehen, sieht es wie folgt aus.
Dieses Mal werden wir kategoriale Variablen nicht klar in sequentielle Variablen und nominale Variablen unterscheiden, sondern sie als kategoriale Variablen und kontinuierliche Variablen verarbeiten.
Wie oben erwähnt, müssen kategoriale Variablen für maschinelles Lernen quantifiziert werden.
Es gibt verschiedene Quantifizierungstechniken, aber dieses Mal werden wir einfach jede Variable indizieren.
↓ Ein solches Bild.
Schreiben wir nun den Code, um die kategorialen Variablen zu quantifizieren. Führen Sie zunächst den folgenden Code aus.
import org.apache.spark.ml.feature.StringIndexer;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
public class GBTRegressionStep02 {
public static void main(String[] args) {
System.setProperty("hadoop.home.dir", "c:\\Temp\\winutil\\");
org.apache.log4j.Logger.getLogger("org").setLevel(org.apache.log4j.Level.ERROR);
org.apache.log4j.Logger.getLogger("akka").setLevel(org.apache.log4j.Level.ERROR);
SparkSession spark = SparkSession
.builder()
.appName("GradientBoostingTreeGegression")
.master("local[*]")
.getOrCreate();
Dataset<Row> dataset = spark
.read()
.format("csv")
.option("header", "true")
.option("inferSchema", "true")
.load("dataset/gem_price_ja.csv");
StringIndexer materialIndexer = new StringIndexer()// (1)
.setInputCol("material")// (2)
.setOutputCol("materialIndex");// (3)
Dataset<Row> materialIndexAddedDataSet = materialIndexer.fit(dataset).transform(dataset);// (4)
materialIndexAddedDataSet.show(10);// (5)
}
}
** (1) ** *** ・ ・ Verwenden Sie *** StringIndexer ***, um kategoriale Variablen zu quantifizieren (zu indexieren). Es hat die Aufgabe, eine bestimmte Variable einzugeben und das codierte (konvertierte) Ergebnis als eine andere Variable auszugeben. Das Codieren ist hier nur ein Vorgang zum Konvertieren einer Zeichenfolge in einen numerischen Wert.
** (2) ** ***. SetInputCol ("Material") *** ・ ・ ・ Geben Sie den Variablennamen an, der in diesen *** StringIndexer *** eingegeben werden soll. Die ** Variablen ** können als ** Spalten ** der Tabelle betrachtet werden, da sie sich beim Laden der CSV-Daten in Spark in einem tabellarischen ** Datensatz ** befinden. col ist ** column ** col, nicht wahr? Mit anderen Worten, der Spaltenname auf der Eingabeseite von *** StringIndexer ** ist *** "Material" ***
** (3) ** ***. SetOutputCol ("materialIndex") *** ・ ・ ・ Geben Sie hier den Spaltennamen auf der Ausgabeseite an.
** (4) ** ・ ・ ・ ** Erstellen Sie ein Lernmodell zum Digitalisieren kategorialer Variablen mit der Methode fit () **. Wenn dem resultierenden Trainingsmodell mit der Transformationsmethode ein Datensatz zugewiesen wird, wird ein neuer Datensatz generiert.
Erstellen Sie ein Lernmodell zur Quantifizierung kategorialer Variablen mit der Anpassungsmethode
aber, Hier ist die ** fit () ** -Methode des *** StringIndexer *** -Objekts mit dem Namen ** materialIndexer ** offensichtlich, wird jedoch nicht gelernt. Es wird einfach ein ** Gerät ** [^ 2] erstellt, das die als kategoriale Variable angegebene Zeichenfolge digitalisiert.
[^ 2]: *** StringIndexer *** erbt eine Klasse namens ** Estimator **. ** Estimator ** ist ursprünglich eine Klasse für ** Lernende **, aber bei der Pipeline-Verarbeitung, die eine Funktion von ** spark.ml ** ist, wie *** StringIndexer *** Durch die Ausstattung des Vorverarbeitungssystems und des Lernenden mit derselben Schnittstelle ist es eine solche Schnittstelle, um den Ablauf von ** Vorverarbeitung → Vorverarbeitung → Lernen ** als Pipeline zu realisieren.
Bei der Methode ** transform ** wird der Prozess zum Erstellen einer neuen indizierten Variablen mit dem Namen ** materialIndex ** aus dem Spaltennamen ** material ** in dem tatsächlich eingegebenen Datensatz ausgeführt.
Ich denke, das ist am unklarsten, aber ich werde die Bedeutung später verstehen, also ist es jetzt mit einem Zauber in Ordnung.
** (5) ** ・ ・ ・ ** Zeigt den Datensatz nach der Verarbeitung von StringIndexer ** an.
Wenn ich den Code ausführe, sieht er folgendermaßen aus:
Rechts wurde eine Spalte mit dem Namen ** materialIndex ** hinzugefügt!
Auf diese Weise können kategoriale Variablen beim maschinellen Lernen nur verwendet werden, wenn sie auf irgendeine Weise quantifiziert werden, sodass auch andere kategoriale Variablen quantifiziert werden.
Also werde ich versuchen, andere kategoriale Variablen ** Form, Marke, Shop ** mit *** StringIndexer ** auf die gleiche Weise zu quantifizieren (zu indizieren).
Dann wird es wie folgt sein
import org.apache.spark.ml.feature.StringIndexer;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
public class GBTRegressionStep02_part02 {
public static void main(String[] args) {
SparkSession spark = SparkSession
.builder()
.appName("GradientBoostingTreeGegression")
.master("local[*]")
.getOrCreate();
Dataset<Row> dataset = spark
.read()
.format("csv")
.option("header", "true")
.option("inferSchema", "true")
.load("dataset/gem_price_ja.csv");
StringIndexer materialIndexer = new StringIndexer()// (1)
.setInputCol("material")
.setOutputCol("materialIndex");
StringIndexer shapeIndexer = new StringIndexer()// (2)
.setInputCol("shape")
.setOutputCol("shapeIndex");
StringIndexer brandIndexer = new StringIndexer()// (3)
.setInputCol("brand")
.setOutputCol("brandIndex");
StringIndexer shopIndexer = new StringIndexer()// (4)
.setInputCol("shop")
.setOutputCol("shopIndex");
Dataset<Row> dataset1 = materialIndexer.fit(dataset).transform(dataset);// (5)
Dataset<Row> dataset2 = shapeIndexer.fit(dataset).transform(dataset1);// (6)
Dataset<Row> dataset3 = brandIndexer.fit(dataset).transform(dataset2);// (7)
Dataset<Row> dataset4 = shopIndexer.fit(dataset).transform(dataset3);// (8)
dataset4.show(10);
}
}
Für ** (1) bis (4) ** wird *** StringIndexer *** für jede Variable vorbereitet. ** (5) - (8) ** werden nacheinander in der Reihenfolge ** materialIndexer → shapeIndexer → brandIndexer → shopIndexer ** indiziert, um einen neuen Datensatz zu erstellen.
Wenn Sie dies tun, erhalten Sie:
Sie können sehen, dass rechts ** materialIndex, shapeIndex, brandIndex, shopIndex ** hinzugefügt wurden.
Übrigens, ↓ Ist das etwas, was nicht geht?
Dataset<Row> dataset1 = materialIndexer.fit(dataset).transform(dataset);// (5)
Dataset<Row> dataset2 = shapeIndexer.fit(dataset).transform(dataset1);// (6)
Dataset<Row> dataset3 = brandIndexer.fit(dataset).transform(dataset2);// (7)
Dataset<Row> dataset4 = shopIndexer.fit(dataset).transform(dataset3);// (8)
Wie hübsch.
Wenn ein bestimmter Prozess abgeschlossen ist, z. B. ** materialIndexer → shapeIndexer → brandIndexer → shopIndexer **, können Sie intelligenter schreiben, dass der nächste Prozess mit diesem Prozess als Eingabe ausgeführt wird.
Das ist der Mechanismus namens ** Pipeline **, den wir als nächstes sehen werden.
↓ Verarbeitung
Before
Dataset<Row> dataset1 = materialIndexer.fit(dataset).transform(dataset);
Dataset<Row> dataset2 = shapeIndexer.fit(dataset).transform(dataset1);
Dataset<Row> dataset3 = brandIndexer.fit(dataset).transform(dataset2);
Dataset<Row> dataset4 = shopIndexer.fit(dataset).transform(dataset3);
Sie können es mit *** Pipeline *** als ↓ umschreiben.
After
Pipeline pipeline = new Pipeline()
.setStages(new PipelineStage[] { materialIndexer, shapeIndexer, brandIndexer, shopIndexer });// (1)
PipelineModel pipelineModel = pipeline.fit(dataset);// (2)
Dataset<Row> indexedDataset = pipelineModel.transform(dataset);// (3)
** (1) ** ・ ・ ・ Erstellen Sie ein *** Pipeline *** -Objekt wie dieses und beschreiben Sie *** StringIndexer *** in der Reihenfolge, in der Sie die Verarbeitung mit *** setStages *** ausführen möchten. Ich werde. Durch einfaches Anordnen auf diese Weise können diese Prozessreihen als Gruppe als *** Pipeline *** ausgeführt werden.
** (2) ** ・ ・ ・ *** Holen Sie sich das PipelineModel mit der Pipeline # fit ***. Zu diesem Zeitpunkt verwende ich immer noch nur *** StringIndexer ***, daher habe ich keine Verarbeitung zum Lernen hinzugefügt, aber wenn die Verarbeitung zum Lernen enthalten ist, kann ich sie mit der *** fit () *** -Methode *** erhalten PipelineModel *** bezeichnet ein Trainingsmodell, das auf dem angegebenen Datensatz basiert.
** (3) ** Pipeline ・ ・ *** Wenn die PipelineModel # -Transformation *** ausgeführt wird, wird eine Reihe von *** StringIndexer *** -Prozessen gleichzeitig ausgeführt, und als Ergebnis wird ein neuer Datensatz erstellt. Dies bedeutet auch, dass das Trainingsmodell auf den angegebenen Datensatz angewendet wird, wenn die Pipeline eine Verarbeitung für das Training enthält.
Der Quellcode und die Ausführungsergebnisse sind unten aufgeführt.
import org.apache.spark.ml.Pipeline;
import org.apache.spark.ml.PipelineModel;
import org.apache.spark.ml.PipelineStage;
import org.apache.spark.ml.feature.StringIndexer;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
public class GBTRegressionStep02_part03 {
public static void main(String[] args) {
System.setProperty("hadoop.home.dir", "c:\\Temp\\winutil\\");
org.apache.log4j.Logger.getLogger("org").setLevel(org.apache.log4j.Level.ERROR);
org.apache.log4j.Logger.getLogger("akka").setLevel(org.apache.log4j.Level.ERROR);
SparkSession spark = SparkSession
.builder()
.appName("GradientBoostingTreeGegression")
.master("local[*]")
.getOrCreate();
Dataset<Row> dataset = spark
.read()
.format("csv")
.option("header", "true")
.option("inferSchema", "true")
.load("dataset/gem_price_ja.csv");
StringIndexer materialIndexer = new StringIndexer()
.setInputCol("material")
.setOutputCol("materialIndex");
StringIndexer shapeIndexer = new StringIndexer()
.setInputCol("shape")
.setOutputCol("shapeIndex");
StringIndexer brandIndexer = new StringIndexer()
.setInputCol("brand")
.setOutputCol("brandIndex");
StringIndexer shopIndexer = new StringIndexer()
.setInputCol("shop")
.setOutputCol("shopIndex");
Pipeline pipeline = new Pipeline()
.setStages(new PipelineStage[] { materialIndexer, shapeIndexer, brandIndexer, shopIndexer });// (1)
PipelineModel pipelineModel = pipeline.fit(dataset);// (2)
Dataset<Row> indexedDataset = pipelineModel.transform(dataset);// (3)
indexedDataset.show(10);
}
}
Ausführungsergebnis
Das Ergebnis ist das gleiche, weil sie semantisch dasselbe tun.
Nun, der Ausführungsteil des Prozesses wurde mit *** Pipeline *** aktualisiert, aber der folgende Teil ist auch etwas redundant.
StringIndexer materialIndexer = new StringIndexer()
.setInputCol("material")
.setOutputCol("materialIndex");
StringIndexer shapeIndexer = new StringIndexer()
.setInputCol("shape")
.setOutputCol("shapeIndex");
StringIndexer brandIndexer = new StringIndexer()
.setInputCol("brand")
.setOutputCol("brandIndex");
StringIndexer shopIndexer = new StringIndexer()
.setInputCol("shop")
.setOutputCol("shopIndex");
Pipeline pipeline = new Pipeline()
.setStages(new PipelineStage[] { materialIndexer, shapeIndexer, brandIndexer, shopIndexer });/
Dies ist eher ein Java-Schreibproblem als Spark, aber lassen Sie es uns etwas sauberer machen.
Ich habe es wie folgt umgeschrieben.
List<String> categoricalColNames = Arrays.asList("material", "shape", "brand", "shop");// (1)
List<StringIndexer> stringIndexers = categoricalColNames.stream()
.map(col -> new StringIndexer()
.setInputCol(col)
.setOutputCol(col + "Index"))// (2)
.collect(Collectors.toList());
Pipeline pipeline = new Pipeline()
.setStages(stringIndexers.toArray(new PipelineStage[0]));// (3)
** (1) ** ・ ・ ・ Setzen Sie den Namen der Kategorievariablen auf List
** (2) ** List ・ ・ *** List # stream *** wird verwendet, um *** StringIndexer *** zu generieren. In *** setOutputCol *** lautet der Spaltenname auf der Ausgabeseite ** Kategorievariablenname + "Index" ** (dh ** materialIndex, shapeIndex, brandIndex, shopIndex **). Das Verarbeitungsergebnis ist ** Liste ** von *** StringIndexer ***.
** (3) ** ・ ・ ・ Auf die Pipeline-Stufe setzen, so dass es sich um ein Array von *** StringIndexer *** handelt
Der Quellcode dieser Zeit ist also wie folgt zusammengefasst. Es war ziemlich erfrischend.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.spark.ml.Pipeline;
import org.apache.spark.ml.PipelineModel;
import org.apache.spark.ml.PipelineStage;
import org.apache.spark.ml.feature.StringIndexer;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
public class GBTRegressionStep02_part04 {
public static void main(String[] args) {
// System.setProperty("hadoop.home.dir", "c:\\Temp\\winutil\\");//for windows
org.apache.log4j.Logger.getLogger("org").setLevel(org.apache.log4j.Level.ERROR);
org.apache.log4j.Logger.getLogger("akka").setLevel(org.apache.log4j.Level.ERROR);
SparkSession spark = SparkSession
.builder()
.appName("GradientBoostingTreeGegression")
.master("local[*]")
.getOrCreate();
Dataset<Row> dataset = spark
.read()
.format("csv")
.option("header", "true")
.option("inferSchema", "true")
.load("dataset/gem_price_ja.csv");
List<String> categoricalColNames = Arrays.asList("material", "shape", "brand", "shop");
List<StringIndexer> stringIndexers = categoricalColNames.stream()
.map(col -> new StringIndexer()
.setInputCol(col)
.setOutputCol(col + "Index"))
.collect(Collectors.toList());
Pipeline pipeline = new Pipeline()
.setStages(stringIndexers.toArray(new PipelineStage[0]));
PipelineModel pipelineModel = pipeline.fit(dataset);
Dataset<Row> indexedDataset = pipelineModel.transform(dataset);
indexedDataset.show(10);
}
}
Wenn Sie dies tun, erhalten Sie weiterhin einen Datensatz mit allen indizierten kategorialen Variablen.
Ich habe bereits erwähnt, dass kategoriale Variablen in Ordinalvariablen und Nominalvariablen unterteilt werden können. Welche Art von Richtlinie weist Spark's ** StringIndexer ** Indexnummern zu? Ist es?
** StringIndexer ** ordnet nach Nummerierung als Index, aber die Standardreihenfolge ist ** Häufigkeit des Auftretens **.
Zusätzlich zur ** Häufigkeit des Auftretens ** können Sie auch die ** alphabetische Reihenfolge ** angeben.
Ein Einstellungsbeispiel ist unten gezeigt.
Häufigkeit des Auftretens-absteigende Reihenfolge(Standard)
StringIndexer materialIndexer1 = new StringIndexer()
.setStringOrderType("frequencyDesc")
.setInputCol("material")
.setOutputCol("materialIndex");
Alphabetischer Reihenfolge-absteigende Reihenfolge
StringIndexer materialIndexer2 = new StringIndexer()
.setStringOrderType("alphabetDesc")
.setInputCol("material")
.setOutputCol("materialIndex");
Alphabetischer Reihenfolge-aufsteigende Reihenfolge
StringIndexer materialIndexer3 = new StringIndexer()
.setStringOrderType("alphabetAsc")
.setInputCol("material")
.setOutputCol("materialIndex");
Ich werde es diesmal nicht verwenden, aber wenn Sie die Indexreihenfolge aussagekräftig machen möchten, können Sie die Variablennamen anpassen und nach ** setStringOrderType ** sortieren.
** Fortsetzung von Nächstes Mal "# 3 Trainiere mit Trainingsdaten und mache [Preisschätzungs-Engine]" **
Nächstes Mal werden wir die Daten tatsächlich trainieren und eine "Preisschätzungs-Engine" erstellen.
Recommended Posts