[JAVA] [Maschinelles Lernen mit Apache Spark] Verknüpfen Sie die Wichtigkeit (Feature-Wichtigkeit) einer Baummodellvariablen mit dem Variablennamen (erklärender Variablenname).

Überblick

Umgebung

Modelle, die die Methode ** featureImportances ** verwenden können

** Funktionsbedeutungen ** können von ** Apache Spark ** mithilfe des folgenden baumbasierten Lernmodells berechnet werden.

GBTRegressionModel < / td> Gradientenverstärkendes Baumregressionsmodell
GBTClassificationModel < / td> Gradientenverstärkendes Baumklassifizierungsmodell
RandomForestRegressionModel < / td> Zufälliges Waldregressionsmodell
RandomForestClassificationModel < / td> Zufälliges Waldklassifizierungsmodell
DecisionTreeRegressionModel < / td> Regressionsmodell des Entscheidungsbaums
DecisionTreeClassificationModel < / td> Bestimmen des Baumklassifizierungsmodells

Welche Bedeutung hat eine Variable (** Feature Importance **)?

Der praktische Teil des Baumsystemalgorithmus besteht darin, dass [berechnet] werden kann (https: :), welche Variable beim Erstellen des Modells als Ergebnis des Trainings als "Wichtigkeit der Variablen (** Feature Importance **)" wichtig war. //web.stanford.edu/~hastie/ElemStatLearn/printings/ESLII_print12.pdf) (S.593).

Da jedoch zufällige Wälder und Bäume mit Gradientenverstärkung Methoden sind, die mehrere Modelle kombinieren, die als ** Ensemble-Lernen ** bezeichnet werden, entspricht die Bedeutung von Variablen (** Merkmalsbedeutung **) dem Regressionskoeffizienten. Es ist zu beachten, dass es sich nicht um einen Index für die Suche nach einer direkten Interpretation handelt.

Methode, um die Wichtigkeit einer Variablen zu ermitteln (** Feature Importance **)

Das Trainingsmodell, das durch Training von ** RandomForest ** in ** spark.ml ** erhalten wurde, z. B. ** RandomForestRegressionModel ** -Klasse, verfügt über die ** RandomForestRegressionModel # featureImportances ** -Methode, wenn Random Forest als Algorithmus verwendet wird. Gibt es.

Durch Aufrufen dieser Methode kann die Wichtigkeit der Variablen (** Feature Importance **) berechnet werden.

Übrigens ist der Rückgabewert der ** RandomForestRegressionModel # featureImportances ** -Methode vom Typ ** SparseVector **, und da der Vektor nur die numerische Komponente enthält, die die Wichtigkeit angibt, sind der numerische Wert und welche Variablen spezifisch. Es ist schwer zu verstehen, ob es unterstützt wird. Es ist schwer zu sagen, ob es da ist.

In diesem Dokument werden daher ** Funktionsbedeutungen ** mit Variablennamen verknüpft.

Bereiten Sie die Variablen, die an die Argumente übergeben werden sollen, in drei Schritten vor, um sie zuzuordnen.

Es wird davon ausgegangen, dass das Modellobjekt mit dem Namen randomForestRegressionModel unter der Voraussetzung erworben wurde, dass das Lernen abgeschlossen wurde.

** SCHRITT 1 ** Holen Sie sich zuerst ** Feature Importances ** wie folgt.

Vector importances=randomForestRegressionModel.featureImportances();

** SCHRITT 2 ** Als nächstes erhalten Sie den Variablennamen, der als Feature-Menge verwendet wird. (Da es sich um einen Variablennamen handelt, für den Sie sich ursprünglich entschieden haben, können Sie ihn hart codieren.)

String featuresCol = this.randomForestRegressionModel.getFeaturesCol()

** SCHRITT 3 ** Holen Sie sich endlich das Schema

StructType schema = predictions.schema();

Übergeben Sie die drei, die Sie gerade vorbereitet haben, an die folgende Methode. Diese Methode wird zum Verknüpfen (plus Sortieren) verwendet.

List<Importance> zipImportances(Vector featureImportances, String featuresCol, StructType schema) {

    final int indexOfFeaturesCol = (Integer) schema.getFieldIndex(featuresCol).get();

    final StructField featuresField = schema.fields()[indexOfFeaturesCol];

    final Metadata metadata = featuresField
            .metadata();

    final Metadata featuresFieldAttrs = metadata
            .getMetadata("ml_attr")
            .getMetadata("attrs");

    final Map<Integer, String> idNameMap = new HashMap<>();

    final String[] fieldKeys = { "nominal", "numeric", "binary" };

    final Collector<Metadata, ?, HashMap<Integer, String>> metaDataMapperFunc = Collectors
            .toMap(
                    metaData -> (int) metaData.getLong("idx"), // key of map
                    metaData -> metaData.getString("name"), // value of map
                    (oldVal, newVal) -> newVal,
                    HashMap::new);

    for (String fieldKey : fieldKeys) {
        if (featuresFieldAttrs.contains(fieldKey)) {
            idNameMap.putAll(Arrays
                    .stream(featuresFieldAttrs.getMetadataArray(fieldKey))
                    .collect(metaDataMapperFunc));
        }
    }

    final double[] importanceScores = featureImportances.toArray();

    final List<Importance> rawImportanceList = IntStream
            .range(0, importanceScores.length)
            .mapToObj(idx -> new Importance(idx, idNameMap.get(idx), importanceScores[idx], 0))
            .collect(Collectors.toList());

    final List<Importance> descSortedImportanceList = rawImportanceList
            .stream()
            .sorted(Comparator.comparingDouble((Importance ifeature) -> ifeature.score).reversed())
            .collect(Collectors.toList());

    for (int i = 0; i < descSortedImportanceList.size(); i++) {
        descSortedImportanceList.get(i).rank = i;
    }

    final List<Importance> finalImportanceList;

    switch (this.sort) {
    case ASCENDING:
        final List<Importance> ascSortedImportantFeatureList = descSortedImportanceList
                .stream()
                .sorted(Comparator.comparingDouble((Importance ifeature) -> ifeature.score))
                .collect(Collectors.toList());

        finalImportanceList = ascSortedImportantFeatureList;
        break;
    case DESCENDING:
        finalImportanceList = descSortedImportanceList;
        break;
    case UNSORTED:
    default:
        finalImportanceList = rawImportanceList;
        break;
    }
    return finalImportanceList;

}

Der Schlüssel zu dieser Methode

Der Schlüssel zu dieser Methode lautet wie folgt.

final StructField featuresField = schema.fields()[indexOfFeaturesCol];

final Metadata metadata = featuresField
        .metadata();

final Metadata featuresFieldAttrs = metadata
        .getMetadata("ml_attr")
        .getMetadata("attrs");

** Schema ** speichert die Struktur des Datensatzes, es gibt jedoch eine Variable als Merkmalsgröße zum Lernen, und die Metadaten (Entwurfsinformationen) davon werden extrahiert und die Position (Index) der Daten wird extrahiert. Und erhalten Sie die Zuordnungsinformationen der entsprechenden Variablen.

Im Schema gespeicherte Metadaten

Was mit den tatsächlichen Metadaten passiert, kann im folgenden JSON-Format extrahiert werden. (Da sich das Format abhängig von dem in der Pipeline-Verarbeitung enthaltenen Transformer ändert, ist das folgende Beispiel)

MetaData-Beispiel(Beispiel bei der Vorhersage des Preises von Schmuckzubehör)



{
   "ml_attr":{
      "attrs":{
         "numeric":[
            {
               "idx":0,
               "name":"weight"
            }
         ],
         "nominal":[
            {
               "vals":[
                  "Platin",
                  "Gold",
                  "Silber",
                  "Dia"
               ],
               "idx":1,
               "name":"materialIndex"
            },
            {
               "vals":[
                  "Brosche",
                  "Halskette",
                  "Ohrringe",
                  "Ring",
                  "Armband"
               ],
               "idx":2,
               "name":"shapeIndex"
            },
            {
               "vals":[
                  "Inländische berühmte Marke",
                  "Übersee super berühmte Marke",
                  "Keine Marke",
                  "Berühmte Marken aus Übersee"
               ],
               "idx":3,
               "name":"brandIndex"
            },
            {
               "vals":[
                  "Kaufhaus",
                  "Direkt verwalteter Laden",
                  "Billiger Laden"
               ],
               "idx":4,
               "name":"shopIndex"
            }
         ]
      },
      "num_attrs":5
   }
}

Wie Sie in diesen Daten sehen können, können Sie das Paar von ** idx ** und ** name ** erhalten. Wenn Sie es also mit ** Vector ** abbilden, das Sie mit der ** FeatureImportances ** -Methode erhalten haben, sieht es wie folgt aus. Aufgrund eines bestimmten Lernens ist es möglich zu wissen, wie wichtig der Variablenname (** Name ) ist ( Punktzahl **).

Erläuterung der Rangfolge der variablen Wichtigkeit


FeatureInfo [rank=0, score=0.3015643580333446, name=weight]
FeatureInfo [rank=1, score=0.2707593044437997, name=materialIndex]
FeatureInfo [rank=2, score=0.20696065038166056, name=brandIndex]
FeatureInfo [rank=3, score=0.11316392134864546, name=shapeIndex]
FeatureInfo [rank=4, score=0.10755176579254973, name=shopIndex]

Zusammenfassung

Ganzer Quellcode

Der Quellcode ist unten https://github.com/riversun/spark-ml-feature-importance-helper

Maven Auch im Maven-Repository erhältlich

<dependency>
	<groupId>org.riversun</groupId>
	<artifactId>spark-ml-feature-importance-helper</artifactId>
	<version>1.0.0</version>
</dependency>

Recommended Posts

[Maschinelles Lernen mit Apache Spark] Verknüpfen Sie die Wichtigkeit (Feature-Wichtigkeit) einer Baummodellvariablen mit dem Variablennamen (erklärender Variablenname).
Einführung in das maschinelle Lernen mit Spark "Price Estimation" # 2 Datenvorverarbeitung (Umgang mit Kategorievariablen)
[Maschinelles Lernen mit Apache Spark] Sparse Vector (spärlicher Vektor) und Dense Vector (dichter Vektor)
Finden Sie mit Kotlin die Anzahl der Tage in einem Monat