web-dev-qa-db-ja.com

VectorAssemblerの出力からSpark MLの列名に機能をマップする方法は?

PySparkで線形回帰を実行しようとしています。データセットの各列の係数、P値、t値などの要約統計を含むテーブルを作成します。ただし、線形回帰モデルをトレーニングするために、SparkのVectorAssemblerを使用して特徴ベクトルを作成する必要があり、各行に1つの特徴ベクトルとターゲット列があります。 Sparkの組み込みの回帰要約統計にアクセスしようとすると、これらの統計のそれぞれの数値の非常に生のリストが表示され、どの属性がどの値に対応するかを知る方法はありません。多数の列。これらの値を列名にマップするにはどうすればよいですか?

たとえば、現在の出力は次のようになります。

係数:[-187.807832407、-187.058926726,85.1716641376,10595.3352802、-127.258892837、-39.2827730493、-1206.47228704,33.7078197705,99.9956812528]

P値:[0.0、0.0、0.0、0.0、0.0、0.0、0.0、0.18589731365614548、0.275173571416679、0.0]

t統計:[-23.348593508995318、-44.72813283953004、19.836508234714472、144.49248881747755、-16.547272230754242、-9.560681351483941、-19.563547400189073、1.3228378389036228、1.0912415361190977、20.383256127350474]

係数の標準誤差:[8.043646497811427、4.182131353367049、4.293682291754585、73.32793120907755、7.690626652102948、4.108783841348964、61.669402913526625、25.481445101737247、91.63478289909655、609.7007361468519]

これらの数値は、対応する属性がわからない限り、何の意味もありません。しかし、私のDataFrameには、スパースベクトルの行を含む「features」という1つの列しかありません。

ワンホットエンコードされた機能がある場合、これはさらに大きな問題です。長さnのエンコードの変数が1つある場合、対応するn個の係数/ p値/ t値などが得られるためです。

20
charmander

今日現在、Sparkはそれを実行できるメソッドを提供していないため、独自に作成する必要がある場合。データが次のようになっているとします。

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"])

そして、次のパイプラインを使用して処理されます:

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)

LinearRegressionModelを取得:

lrm = model.stages[-1]

データを変換します。

transformed =  model.transform(df)

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())))

そして出力にマップします:

[(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

ここで列の実際の順序を見ることができます

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

通常、["binary]と[" numeric "]の2つのクラスがあります。

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

すべての列の正確な順序を与える必要があります

3
pratiklodha