私はPySparkのドキュメントからいくつかの相互検証コードをいじくり回し、PySparkにどのモデルが選択されたかを教えてもらうようにしています:
from pyspark.ml.classification import LogisticRegression
from pyspark.ml.evaluation import BinaryClassificationEvaluator
from pyspark.mllib.linalg import Vectors
from pyspark.ml.tuning import ParamGridBuilder, CrossValidator
dataset = sqlContext.createDataFrame(
[(Vectors.dense([0.0]), 0.0),
(Vectors.dense([0.4]), 1.0),
(Vectors.dense([0.5]), 0.0),
(Vectors.dense([0.6]), 1.0),
(Vectors.dense([1.0]), 1.0)] * 10,
["features", "label"])
lr = LogisticRegression()
grid = ParamGridBuilder().addGrid(lr.regParam, [0.1, 0.01, 0.001, 0.0001]).build()
evaluator = BinaryClassificationEvaluator()
cv = CrossValidator(estimator=lr, estimatorParamMaps=grid, evaluator=evaluator)
cvModel = cv.fit(dataset)
これをPySpark Shellで実行すると、線形回帰モデルの係数を取得できますが、相互検証手順で選択されたlr.regParam
の値が見つからないようです。何か案は?
In [3]: cvModel.bestModel.coefficients
Out[3]: DenseVector([3.1573])
In [4]: cvModel.bestModel.explainParams()
Out[4]: ''
In [5]: cvModel.bestModel.extractParamMap()
Out[5]: {}
In [15]: cvModel.params
Out[15]: []
In [36]: cvModel.bestModel.params
Out[36]: []
この問題にも遭遇しました。何らかの理由でJavaプロパティを呼び出す必要があることがわかりました。理由はわかりません。
_from pyspark.ml.tuning import TrainValidationSplit, ParamGridBuilder, CrossValidator
from pyspark.ml.regression import LinearRegression
from pyspark.ml.evaluation import RegressionEvaluator
evaluator = RegressionEvaluator(metricName="mae")
lr = LinearRegression()
grid = ParamGridBuilder().addGrid(lr.maxIter, [500]) \
.addGrid(lr.regParam, [0]) \
.addGrid(lr.elasticNetParam, [1]) \
.build()
lr_cv = CrossValidator(estimator=lr, estimatorParamMaps=grid, \
evaluator=evaluator, numFolds=3)
lrModel = lr_cv.fit(your_training_set_here)
bestModel = lrModel.bestModel
_
必要なパラメーターを印刷します。
_>>> print 'Best Param (regParam): ', bestModel._Java_obj.getRegParam()
0
>>> print 'Best Param (MaxIter): ', bestModel._Java_obj.getMaxIter()
500
>>> print 'Best Param (elasticNetParam): ', bestModel._Java_obj.getElasticNetParam()
1
_
これは、extractParamMap()
などの他のメソッドにも適用されます。彼らはすぐにこれを修正する必要があります。
CvModel3Dayがモデル名であると仮定すると、Spark Scala
val params = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].extractParamMap()
val depth = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].getMaxDepth
val iter = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].getMaxIter
val bins = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].getMaxBins
val features = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].getFeaturesCol
val step = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].getStepSize
val samplingRate = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].getSubsamplingRate
これはwernerchaoの回答ほど良くないかもしれません(変数にハイパーパラメーターを保存するのは便利ではないため)が、この方法でクロス検証モデルの最良のハイパーパラメーターをすばやく見ることができます:
cvModel.getEstimatorParamMaps()[ np.argmax(cvModel.avgMetrics) ]
また、この壁で頭をバウンスしましたが、残念ながらspecificモデルのパラメーターはspecificしか取得できません。ロジスティック回帰の場合、切片と重みにアクセスできますが、悲しいことにregParamを取得できません。これは、次の方法で実行できます。
best_lr = cv.bestModel
#get weigths
best_lr.weights
>>>DenseVector([3.1573])
#or better
best_lr.coefficients
>>>DenseVector([3.1573])
#get intercept
best_lr.intercept
>>>-1.0829958115287153
前に書いたように、各モデルには抽出できるパラメーターがほとんどありません。パイプラインからの関連モデルの全体的な取得(たとえば、クロスバリデーターがパイプライン上で実行される場合のcv.bestModel)は、次の方法で実行できます。
best_pipeline = cv.bestModel
best_pipeline.stages
>>>[Tokenizer_4bc8884ad68b4297fd3c,CountVectorizer_411fbdeb4100c2bfe8ef, PCA_4c538d67e7b8f29ff8d0,LogisticRegression_4db49954edc7033edc76]
各モデルは、単純なリストのインデックス付けによって取得されます
best_lr = best_pipeline.stages[3]
これで上記を適用できます。
実際には2つの質問があります。
bestModel
の適合に使用したメタパラメーターは何でしたか。残念ながら、適合推定器(モデル)のpython api)は、推定器のパラメーターへの(簡単な)直接アクセスを許可しないため、後者の質問に答えるのが難しくなります。
ただし、Java api。を使用する回避策があります。完全を期すために、最初に相互検証モデルの完全セットアップを行います。
_%pyspark
from pyspark.ml import Pipeline
from pyspark.ml.classification import LogisticRegression
from pyspark.ml.evaluation import BinaryClassificationEvaluator
from pyspark.ml.tuning import CrossValidator, ParamGridBuilder
logit = LogisticRegression(maxIter=10)
pipeline = Pipeline(stages=[logit])
paramGrid = ParamGridBuilder() \
.addGrid(logit.regParam, [0, 0.01, 0.05, 0.1, 0.5, 1]) \
.addGrid(logit.elasticNetParam, [0.0, 0.1, 0.5, 0.8, 1]) \
.build()
evaluator = BinaryClassificationEvaluator(metricName = 'areaUnderPR')
crossval = CrossValidator(estimator=pipeline,
estimatorParamMaps=paramGrid,
evaluator=evaluator,
numFolds=5)
tuned_model = crossval.fit(train)
model = tuned_model.bestModel
_
getRegParam()
のようなメソッドを明示的に参照せずに、Javaオブジェクトのジェネリックメソッドを使用してパラメーター値を取得できます。
_Java_model = model.stages[-1]._Java_obj
{param.name: Java_model.getOrDefault(Java_model.getParam(param.name))
for param in paramGrid[0]}
_
これにより、次の手順が実行されます。
crossval.fit(..).bestModel.stages[-1]
_Java_obj
_から内部のJavaオブジェクトを取得paramGrid
(辞書のリスト)から構成済みの名前をすべて取得します。最初の行のみが使用されます。実際のグリッドであると仮定すると、各行には同じキーが含まれます。それ以外の場合は、任意の行で使用されたすべての名前を収集する必要があります。Param<T>
_ パラメータ識別子を取得します。Param<T>
_インスタンスを getOrDefault()
関数に渡し、実際の値を取得しますこれは解読に数分かかりましたが、私はそれを理解しました。
from pyspark.ml.tuning import CrossValidator, ParamGridBuilder
# prenotation: I've built out my model already and I am calling the validator ParamGridBuilder
paramGrid = ParamGridBuilder() \
.addGrid(hashingTF.numFeatures, [1000]) \
.addGrid(linearSVC.regParam, [0.1, 0.01]) \
.addGrid(linearSVC.maxIter, [10, 20, 30]) \
.build()
crossval = CrossValidator(estimator=pipeline,\
estimatorParamMaps=paramGrid,\
evaluator=MulticlassClassificationEvaluator(),\
numFolds=2)
cvModel = crossval.fit(train)
prediction = cvModel.transform(test)
bestModel = cvModel.bestModel
#applicable to your model to pull list of all stages
for x in range(len(bestModel.stages)):
print bestModel.stages[x]
#get stage feature by calling correct Transformer then .get<parameter>()
print bestModel.stages[3].getNumFeatures()