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値などが得られるためです。
今日現在、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)]
ここで列の実際の順序を見ることができます
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")
すべての列の正確な順序を与える必要があります