Estoy tratando de ejecutar una regresión lineal en PySpark y quiero crear una tabla que contenga estadísticas de resumen como coeficientes, valores P y valores t para cada columna en mi conjunto de datos. Sin embargo, para entrenar un modelo de regresión lineal, tuve que crear un vector de funciones usando VectorAssembler de Spark, y ahora para cada fila tengo un solo vector de funciones y la columna de destino. Cuando trato de acceder a las estadísticas de resumen de regresión integradas de Spark, me dan una lista muy cruda de números para cada una de estas estadísticas, y no hay forma de saber qué atributo corresponde a qué valor, lo cual es realmente difícil de averiguar manualmente con una gran cantidad de columnas. ¿Cómo asigno estos valores a los nombres de las columnas?
Por ejemplo, tengo mi salida actual como algo como esto:
Coeficientes: [-187.807832407,-187.058926726,85.1716641376,10595.3352802,-127.258892837,-39.2827730493,-1206.47228704,33.7078197705,89295925]
Valor P: [0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,18589731365614548, 0,275173571416679, 0,0]
t-statistic: [-23.348593508995318, -44.72813283953004, 19.836508234714472, 144.49248881747755, -16.547272230754242, -9.560681351483941, -19.563547400189073, 1.3228378389036228, 1.0912415361190977, 20.383256127350474]
Coefficient Standard Errors: [8.043646497811427, 4.182131353367049, 4.293682291754585, 73.32793120907755, 7.690626652102948, 4.108783841348964, 61.669402913526625, 25.481445101737247, 91.63478289909655, 609.7007361468519]
Estos números no significan nada a menos que sepa a qué atributo corresponden. Pero en mi DataFrame solo tengo una columna llamada "características" que contiene filas de vectores dispersos.
Este es un problema cada vez mayor cuando tengo funciones codificadas en caliente, porque si tengo una variable con una codificación de longitud n, obtendré n coeficientes/valores p/valores t correspondientes, etc.
A día de hoy, Spark no proporciona ningún método que pueda hacerlo por ti, así que si tienes que crear el tuyo propio. Digamos que sus datos se ven así:
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"])y se procesa utilizando la siguiente canalización:
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) Obtenga el modelo de LinearRegressionModel :
lrm = model.stages[-1]Transformar los datos:
transformed = model.transform(df)Extraer y aplanar atributos de 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())))y mapear a la salida:
[(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)]Puede ver el orden real de las columnas aquí
df.schema["features"].metadata["ml_attr"]["attrs"]normalmente habrá dos clases, ["binary] & ["numeric"]
pd.DataFrame(df.schema["features"].metadata["ml_attr"]["attrs"]["binary"]+df.schema["features"].metadata["ml_attr"]["attrs"]["numeric"]).sort_values("idx")Debe dar el orden exacto de todas las columnas.
Aquí está la respuesta de una línea:
[x["name"] for x in sorted(train_downsampled.schema["all_features"].metadata["ml_attr"]["attrs"]["binary"]+ train_downsampled.schema["all_features"].metadata["ml_attr"]["attrs"]["numeric"], key=lambda x: x["idx"])]Gracias a @pratiklodha por el núcleo de esto.