pyspark:CrossValidator无法正常工作

时间:2016-07-17 02:43:40

标签: apache-spark pyspark apache-spark-mllib apache-spark-ml

我正在尝试调整ALS的参数,但始终选择第一个参数作为最佳选项

        <<div class="container" style="max-width:700px" >
        <div class="jumbotron" style="center" >

输出:
rmse with cross validation:1.1820489116858794
reg_param:1.0,rmse:1.1820489116858794
reg_param:0.005,rmse:0.001573816765686575
reg_param:2.0,rmse:2.1056964491942787

任何帮助?

提前致谢,

3 个答案:

答案 0 :(得分:2)

抛开其他问题,您只是没有使用足够的数据来执行有意义的交叉验证和评估。正如我在Spark ALS predictAll returns empty中解释和说明的那样,当训练集中缺少用户或项目时,ALS无法提供预测。

这意味着在交叉验证期间的每个拆分都将具有未定义的预测,并且将不确定整体评估。因为CrossValidator将返回第一个可能的模型,因为你训练的所有模型从它的角度看同样糟糕。

答案 1 :(得分:1)

在CrossValidator中,您将折叠数设置为1.但是,参数numFolds must be >=2。仅使用一次折叠就会失去与分离到训练和测试集的想法。

答案 2 :(得分:0)

我实现了一个Pipeline解决方案,在该方法的最后阶段添加了一个自定义转换器,以便放弃nan的预测。请注意,此实现适用于Spark <2.2.0,因为未引入关键字coldStartStrategy。因此,如果您使用的是Spark == 2.2.0,则不需要其他阶段。

首先,我介绍应用nan放置的自定义转换器。

from pyspark.ml import Transformer

class DropNAPredictions(Transformer):
    def _transform(self, predictedDF):
        nonNullDF = predictedDF.dropna(subset=['prediction', ])
        predictionDF = nonNullDF.withColumn('prediction', nonNullDF['prediction'].cast('double'))
        return predictionDF

现在,我可以使用交叉验证来构建我的管道并进行训练:

dropna = DropNAPredictions()

als = ALS(maxIter=10, userCol="player", itemCol="item", ratingCol="rating", implicitPrefs=False)

pipeline = Pipeline(stages=[als, dropna])
paramGrid = ParamGridBuilder().addGrid(als.regParam, [0.1, 0.05]) \
    .addGrid(als.rank, [1, 3]) \
    .build()

cv = CrossValidator(estimator=pipeline,
                    estimatorParamMaps=paramGrid,
                    evaluator=RegressionEvaluator(labelCol="rating"),
                    numFolds=3)

cvModel = cv.fit(training)

关于持久性的说明:由于自定义转换器,无法保存管道。有一个post讨论了序列化自定义转换器的选项,但是我并没有为解决某个问题而烦恼。作为临时解决方案,您可以仅序列化ALS模型本身,然后在以后通过将自定义转换器添加到管道来重建管道。

bestPipeline = cvModel.bestModel
bestModel = bestPipeline.stages[0]  # extracts the ALS model
bestModel.save("s2s_als_stage")

from pyspark.ml.pipeline import PipelineModel
from pyspark.ml.recommendation import ALSModel

mymodel = ALSModel.load('s2s_als_stage')
pipeline = PipelineModel(stages=[mymodel, dropna])  # dropna is the custom transformer
pred_test = pipeline.transform(test)  # score test data