我正在尝试调整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
任何帮助?
提前致谢,
答案 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