[JAVA] Introduction à l'apprentissage automatique avec Spark "Estimation de prix" # 3 Apprenons avec les données d'entraînement et créons un [moteur d'estimation de prix]

Aperçu

-Introduction à l'apprentissage automatique avec ** Java ** et ** Apache Spark **

environnement

Créer un modèle d'apprentissage automatique

C'est finalement la phase d'apprentissage automatique. Cette fois, nous allons créer un "moteur d'estimation de prix" qui fonctionne réellement.

Dernière fois a exécuté le processus de remplacement de la variable catégorielle représentée par la chaîne de caractères par une valeur numérique dans le pipeline.

Et comme le nom de la variable de catégorie numérisée a été traité de sorte que ** Index ** a été ajouté à la fin (suffixe), L'ensemble de données contient ** materialIndex, shapeIndex, brandIndex, shopIndex, weight, price ** comme variables de type numérique.

Variables explicatives et objectives

Dans cet exemple, nous voulons estimer (prédire) le prix de l'accessoire, mais les données à prévoir (** prix ** ici) sont appelées la ** variable objective **.

Lorsque vous souhaitez estimer (prédire) le prix d'un accessoire, qu'est-ce qui détermine le prix de l'accessoire?

Si l'accessoire est fait de diamant, il sera cher, et plus le bijou ou le métal précieux est lourd, plus il aura de valeur. De plus, si le produit est fabriqué par une marque célèbre, il est susceptible d'avoir une prime.

Comme vous pouvez le voir, il y a quelques raisons, c'est-à-dire ** causes **, au-dessus et en dessous du prix des accessoires.

Les données qui en sont la cause sont appelées la ** variable explicative **.

Cause: variable explicative Résultat ... Variable objective

Alors Les variables de l'ensemble de données sont divisées en variables explicatives et en variables objectives comme suit.

Variables explicatives ... ** materialIndex, shapeIndex, brandIndex, shopIndex, weight ** Objectif variable ・ ・ ・ ** prix **

image.png

Désormais, nous utiliserons ces données pour l'apprentissage.

L'apprentissage est une grande variété de méthodes permettant de découvrir et d'exprimer (bien que pas toujours compréhensibles par l'homme) les relations et les règles entre variables explicatives et variables objectives à l'aide de formules mathématiques et ** d'algorithmes d'apprentissage **. A été proposé.

La relation entre les variables explicatives et les variables objectives acquises par l'apprentissage est appelée le ** modèle d'apprentissage ** (ou modèle d'apprentissage automatique, ou simplement le modèle).

Bien sûr, pour démêler et approximer des relations inconnues, il doit y avoir une quantité considérable de données, donc l'apprentissage automatique est égal ou supérieur à l'algorithme ** la quantité et la qualité des données sont importantes **. C'est dit.

Cette fois-ci, nous préparerons ** l'arbre d'amplification du gradient ** en tant qu'algorithme d'apprentissage et ** 500 données sur le prix des accessoires (aucune valeur manquante) ** en tant que données.

Revenir

Lorsque la variable objectif (= prix) que vous souhaitez prédire par apprentissage automatique est une valeur continue comme cette fois, une telle prédiction est appelée ** régression ** (régression).

Et le modèle d'apprentissage de la régression s'appelle ** Regressor **.

En revanche, lorsque la variable objectif est binaire ou lorsque plusieurs classes (catégories) sont requises, on parle de ** classification ** (classification). Le modèle d'apprentissage pour la classification est appelé ** Classificateur **.

Créer un vecteur de caractéristiques

Il traite plusieurs variables (colonnes) en une seule pour une utilisation dans l'apprentissage.


import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.spark.ml.Pipeline;
import org.apache.spark.ml.PipelineStage;
import org.apache.spark.ml.feature.StringIndexer;
import org.apache.spark.ml.feature.VectorAssembler;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;

public class GBTRegressionStep03_part01 {

  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()
            .setStringOrderType("frequencyDesc")
            .setInputCol(col)
            .setOutputCol(col + "Index"))
        .collect(Collectors.toList());

    String[] indexedCategoricalColNames = stringIndexers// (1)
        .stream()
        .map(StringIndexer::getOutputCol)
        .toArray(String[]::new);

    String[] numericColNames = new String[] { "weight" };// (2)

    VectorAssembler assembler = new VectorAssembler()// (3)
        .setInputCols(array(indexedCategoricalColNames, numericColNames))
        .setOutputCol("features");

    PipelineStage[] indexerStages = stringIndexers.toArray(new PipelineStage[0]);// (5)

    PipelineStage[] pipelineStages = array(indexerStages, assembler);// (6)

    Pipeline pipeline = new Pipeline().setStages(pipelineStages);// (7)

    pipeline.fit(dataset).transform(dataset).show(10);// (8)

  }

  @SuppressWarnings("unchecked")
  public static <T> T[] array(final T[] array1, final T... array2) {
    final Class<?> type1 = array1.getClass().getComponentType();
    final T[] joinedArray = (T[]) Array.newInstance(type1, array1.length + array2.length);
    System.arraycopy(array1, 0, joinedArray, 0, array1.length);
    System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
    return joinedArray;
  }
}

Commentaire de code

** (1) ** ・ ・ ・ *** StringIndexer *** Les noms de colonne de sortie (outputCol) sont regroupés dans un tableau. Ce sera un tableau de noms de colonnes de variables catégorielles quantifiées comme indiqué ci-dessous.

[materialIndex,shapeIndex,brandIndex,shopIndex]

** (2) ** ・ ・ ・ Un tableau de noms de colonnes qui prennent une variable numérique. Cette fois seulement ** poids **

** (3) ** ・ ・ ・ Vectoriser plusieurs variables de type numérique.

Pour *** VectorAssembler # setInputCols *, spécifiez le nom de la colonne que vous souhaitez vectoriser. Ici, tous les noms de colonne ( materialIndex, shapeIndex, brandIndex, shopIndex, weight **) qui sont candidats pour les variables explicatives sont spécifiés [^ 1].

[^ 1]: Selon l'algorithme d'apprentissage automatique, il peut ne pas être possible de bien apprendre à moins d'avoir une bonne compréhension des variables explicatives et de sélectionner les variables explicatives (Sélection des fonctionnalités). Par exemple, une forte corrélation entre les variables explicatives peut poser le problème de la colinéarité multiple (multico). Cette fois, l'algorithme est un système d'arbre de décision (modèle non linéaire) et c'est une partie introductive, j'ai donc inclus toutes les variables explicatives candidates. *** fonction de tableau *** est une fonction pour joindre des tableaux. Le résultat vectorisé est ajouté à l'ensemble de données en tant que nom de colonne spécifié par *** setOutputCol ***.

VectorAssembler assembler = new VectorAssembler()// (3)
    .setInputCols(array(indexedCategoricalColNames, numericColNames))
    .setOutputCol("features");

** (5) - (7) ** ・ ・ ・ Set ** StringIndexer ** et ** VectorAssembler ** dans ** Pipeline **.

PipelineStage[] indexerStages = stringIndexers.toArray(new PipelineStage[0]);// (5)
PipelineStage[] pipelineStages = array(indexerStages, assembler);// (6)
Pipeline pipeline = new Pipeline().setStages(pipelineStages);// (7)

** (8) ** ・ ・ ・ Exécuter ce traitement de pipeline

Le résultat de l'exécution est le suivant.

image.png

Vous pouvez voir qu'une colonne vectorielle appelée ** features ** a été ajoutée.

En d'autres termes, *** VectorAssembler *** fait de plusieurs variables ** weight, materialIndex, shapeIndex, brandIndex, shopIndex ** un seul vecteur avec le nom "** features **".

image.png

Ces ** données similaires aux caractéristiques ** sont appelées un ** vecteur de caractéristiques **.

Construire un modèle d'apprentissage et prévoir les prix

Eh bien, je suis enfin prêt Enfin ** construisez un modèle d'apprentissage ** et prévoyez réellement ** le prix des accessoires ** (retour).

Immédiatement, le code d'apprentissage et de prédiction ressemble à ceci:


import java.lang.reflect.Array;
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.ml.feature.VectorAssembler;
import org.apache.spark.ml.regression.GBTRegressor;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;

public class GBTRegressionStep03_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");

    List<String> categoricalColNames = Arrays.asList("material", "shape", "brand", "shop");

    List<StringIndexer> stringIndexers = categoricalColNames.stream()
        .map(col -> new StringIndexer()
            .setStringOrderType("frequencyDesc")
            .setInputCol(col)
            .setOutputCol(col + "Index"))
        .collect(Collectors.toList());

    String[] indexedCategoricalColNames = stringIndexers
        .stream()
        .map(StringIndexer::getOutputCol)
        .toArray(String[]::new);

    String[] numericColNames = new String[] { "weight" };

    VectorAssembler assembler = new VectorAssembler()
        .setInputCols(array(indexedCategoricalColNames, numericColNames))
        .setOutputCol("features");

    GBTRegressor gbtr = new GBTRegressor()// (1)
        .setLabelCol("price")
        .setFeaturesCol("features")
        .setPredictionCol("prediction");

    PipelineStage[] indexerStages = stringIndexers.toArray(new PipelineStage[0]);

    PipelineStage[] pipelineStages = array(indexerStages, assembler, gbtr);// (2)

    Pipeline pipeline = new Pipeline().setStages(pipelineStages);

    long seed = 0;

    Dataset<Row>[] splits = dataset.randomSplit(new double[] { 0.7, 0.3 }, seed);// (3)

    Dataset<Row> trainingData = splits[0];// (4)
    Dataset<Row> testData = splits[1];// (5)

    PipelineModel pipelineModel = pipeline.fit(trainingData);// (6)

    Dataset<Row> predictions = pipelineModel.transform(testData);// (7)

    predictions.select("id", "material", "shape", "weight", "brand", "shop", "price", "prediction").show(10);// (8)

  }

  @SuppressWarnings("unchecked")
  public static <T> T[] array(final T[] array1, final T... array2) {
    final Class<?> type1 = array1.getClass().getComponentType();
    final T[] joinedArray = (T[]) Array.newInstance(type1, array1.length + array2.length);
    System.arraycopy(array1, 0, joinedArray, 0, array1.length);
    System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
    return joinedArray;
  }
}

Commentaire de code

** (1) ** ・ ・ ・ Créez un estimateur pour ** l'arbre d'amplification de gradient ** pour un apprentissage supervisé. Pour *** setLabelCol *, spécifiez le nom de la colonne ( prix **) que vous souhaitez prédire. Pour *** setFeaturesCol *, spécifiez le nom de colonne ( features ) du vecteur de caractéristiques. *** setPredictionCol *** spécifie un nouveau nom de colonne ( prediction **) pour stocker les résultats de la prédiction.

 GBTRegressor gbtr = new GBTRegressor()// (1)
        .setLabelCol("price")
        .setFeaturesCol("features")
        .setPredictionCol("prediction");

** (2) ** ・ ・ ・ Ajout d'un apprenant (** gbt **) à Pipeline. Désormais, en plus de l'indexation des variables catégorielles et du traitement de vectorisation, l'apprenant est également ajouté lors de la formation.

PipelineStage[] pipelineStages = array(indexerStages, assembler, gbtr);// (2)
Pipeline pipeline = new Pipeline().setStages(pipelineStages);

** (3) ** ・ ・ ・ *** dataset.randomSplit *** divise l'ensemble de données d'origine de manière aléatoire dans un rapport de 70%: 30%

** (4) ** ・ ・ ・ Sur l'ensemble de données divisé, 70% sont utilisés comme données d'entraînement.

** (5) ** ・ ・ ・ Sur l'ensemble de données divisé, 30% sont utilisés comme données de test.

** (6) ** ・ ・ ・ *** Pipeline.fit *** pour mettre les données d'entraînement dans le formateur et l'entraîner. Après la formation, *** pipelineModel *** peut être obtenu en tant que ** modèle d'apprentissage ** entraîné (modèle d'apprentissage automatique). Vous pourrez effectuer une régression (prédiction du ** prix **) à l'aide de ce ** modèle d'apprentissage **.

PipelineModel pipelineModel = pipeline.fit(trainingData);// (6)

** (7) ** ・ ・ ・ *** Exécuter ** prédiction ** (retour) en utilisant le modèle entraîné avec pipelineModel.transform (testData) ***! Prédisez le prix de l'accessoire dans les données de test spécifiées ici. Un ensemble de données contenant les résultats de la prédiction (spécifiquement, la colonne ** prediction **) est renvoyé.

Dataset<Row> predictions = pipelineModel.transform(testData);// (7)

** (8) ** ・ ・ ・ Afficher le résultat de l'exécution. Dans *** show ***, le nom de la colonne que vous souhaitez afficher est spécifié et affiché.

Oui, le résultat d'exécution prévu est le suivant

image.png

La ** prédiction ** à l'extrême droite du tableau et le ** prix ** à la seconde à partir de la droite sont les résultats de prédiction de l'apprentissage automatique et les réponses contenues dans les données d'origine, respectivement.

image.png

La différence entre ** prédiction ** et ** prix ** est la différence entre la prédiction et la réponse, mais je pense que vous pouvez prédire une valeur proche de cela.

Je ne l'ai pas réglé en particulier, mais j'ai fait un simple "moteur d'estimation du prix des accessoires" ^ _ ^

** Continuer à la prochaine fois **

La prochaine fois, j'aimerais traiter des ** indicateurs d'évaluation des résultats d'apprentissage, du réglage des hyper paramètres et de la recherche de grille **.

Recommended Posts

Introduction à l'apprentissage automatique avec Spark "Estimation de prix" # 3 Apprenons avec les données d'entraînement et créons un [moteur d'estimation de prix]
Introduction à l'apprentissage automatique avec Spark "Price Estimate" # 2 Prétraitement des données (gestion des variables de catégorie)
Premiers pas avec le Machine Learning avec Spark "Price Estimate" # 1 Chargement des ensembles de données avec Apache Spark (Java)
J'ai créé une application d'apprentissage automatique avec Dash (+ Docker) part3 ~ Practice ~
Apprendre Ruby avec AtCoder 13 Comment créer un tableau à deux dimensions
J'ai créé une application d'apprentissage automatique avec Dash (+ Docker) part2 ~ Façon basique d'écrire Dash ~
J'ai essayé de créer une application d'apprentissage automatique avec Dash (+ Docker) part1 ~ Construction de l'environnement et vérification du fonctionnement ~
[Introduction à Docker] Créer une image Docker pour l'apprentissage automatique et utiliser le notebook Jupyter
[Apprentissage automatique avec Apache Spark] Vecteur fragmenté (vecteur fragmenté) et vecteur dense (vecteur dense)
[Introduction au développement d'applications Android] Faisons un compteur