web-dev-qa-db-fra.com

Comment mapper des entités de la sortie d'un VectorAssembler vers les noms de colonne dans Spark ML?

J'essaie d'exécuter une régression linéaire dans PySpark et je veux créer un tableau contenant des statistiques récapitulatives telles que les coefficients, les valeurs P et les valeurs t pour chaque colonne de mon ensemble de données. Cependant, afin de former un modèle de régression linéaire, j'ai dû créer un vecteur d'entités en utilisant VectorAssembler de Spark, et maintenant pour chaque ligne j'ai un seul vecteur d'entités et la colonne cible. Lorsque j'essaie d'accéder aux statistiques récapitulatives de régression intégrées de Spark, elles me donnent une liste très brute de nombres pour chacune de ces statistiques, et il n'y a aucun moyen de savoir quel attribut correspond à quelle valeur, ce qui est vraiment difficile à comprendre manuellement avec un grand nombre de colonnes. Comment mapper ces valeurs sur les noms de colonne?

Par exemple, j'ai ma sortie actuelle comme quelque chose comme ceci:

Coefficients: [-187.807832407, -187.058926726,85.1716641376,10595.3352802, -127.258892837, -39.2827730493, -1206.47228704,33.7078197705,99.9956812528]

Valeur P: [0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,18589731365614548, 0,275173571416679, 0,0]

statistique t: [-23.348593508995318, -44.72813283953004, 19.836508234714472, 144.49248881747755, -16.547272230754242, -9.560681351483941, -19.563547400189073, 1.322837838912158363

Erreurs standard de coefficient: [8.043646497811427, 4.182131353367049, 4.293682291754585, 73.32793120907755, 7.690626652102948, 4.108783841348964, 61.669402913526625, 25.481445101737247909, 91.634782868

Ces chiffres ne signifient rien à moins que je sache à quel attribut ils correspondent. Mais dans mon DataFrame je n'ai qu'une seule colonne appelée "features" qui contient des rangées de vecteurs épars.

C'est un problème de plus en plus important lorsque j'ai des fonctionnalités codées à chaud, car si j'ai une variable avec un codage de longueur n, j'obtiendrai n coefficients/valeurs p/valeurs t correspondants, etc.

20
charmander

À ce jour Spark ne fournit aucune méthode qui peut le faire pour vous, donc si vous devez créer la vôtre. Disons que vos données ressemblent à ceci:

import random
random.seed(1)

df = sc.parallelize([(
    random.choice([0.0, 1.0]), 
    random.choice(["a", "b", "c"]),
    random.choice(["foo", "bar"]),
    random.randint(0, 100),
    random.random(),
) for _ in range(100)]).toDF(["label", "x1", "x2", "x3", "x4"])

et est traité à l'aide du pipeline suivant:

from pyspark.ml.feature import StringIndexer, OneHotEncoder, VectorAssembler
from pyspark.ml import Pipeline
from pyspark.ml.regression import LinearRegression

indexers = [
  StringIndexer(inputCol=c, outputCol="{}_idx".format(c)) for c in ["x1", "x2"]]
encoders = [
    OneHotEncoder(
        inputCol=idx.getOutputCol(),
        outputCol="{0}_enc".format(idx.getOutputCol())) for idx in indexers]
assembler = VectorAssembler(
    inputCols=[enc.getOutputCol() for enc in encoders] + ["x3", "x4"],
    outputCol="features")

pipeline = Pipeline(
    stages=indexers + encoders + [assembler, LinearRegression()])
model = pipeline.fit(df)

Obtenez le LinearRegressionModel:

lrm = model.stages[-1]

Transformez les données:

transformed =  model.transform(df)

Extraire et aplatir les attributs ML:

from itertools import chain

attrs = sorted(
    (attr["idx"], attr["name"]) for attr in (chain(*transformed
        .schema[lrm.summary.featuresCol]
        .metadata["ml_attr"]["attrs"].values())))

et mappez à la sortie:

[(name, lrm.summary.pValues[idx]) for idx, name in attrs]
[('x1_idx_enc_a', 0.26400012641279824),
 ('x1_idx_enc_c', 0.06320192217171572),
 ('x2_idx_enc_foo', 0.40447778902400433),
 ('x3', 0.1081883594783335),
 ('x4', 0.4545851609776568)]
[(name, lrm.coefficients[idx]) for idx, name in attrs]
[('x1_idx_enc_a', 0.13874401585637453),
 ('x1_idx_enc_c', 0.23498565469334595),
 ('x2_idx_enc_foo', -0.083558932128022873),
 ('x3', 0.0030186112903237442),
 ('x4', -0.12951394186593695)]
16
user6910411

Vous pouvez voir l'ordre réel des colonnes ici

df.schema["features"].metadata["ml_attr"]["attrs"]

il y aura généralement deux classes, ["binary] & [" numeric "]

pd.DataFrame(df.schema["features"].metadata["ml_attr"]["attrs"]["binary"]+df.schema["features"].metadata["ml_attr"]["attrs"]["numeric"]).sort_values("idx")

Doit donner l'ordre exact de toutes les colonnes

3
pratiklodha