spark的MLlib是其机器学习算法库。
其中协同过滤算法叫做ALS,交替最小二乘法。
下面对算法思路和执行代码进行分析。
算法思想:
1、对于用户、商品、评分构成的打分矩阵。一般来说是稀疏的矩阵,因为用户没有对所有商品打分,很多地方评分是未知数。
2、我们的目的是要将这个打分矩阵填满,从而预测用户对某个商品的打分,继而进行推荐。
3、计算这个原始矩阵的计算量是非常巨大的,而且没有必要。我们希望计算出其低秩矩阵,从而宏观上勾勒出用户和商品之间的关联关系,即相似度。
通过这个相似度,构成推荐系统的基本依据。
4、计算时,采用最小二乘法。
由于要优化的公式变量很多,我们采取固定其一,优化其他变量的方式寻求最优值的方式求解。所以较交替最小二乘法。
计算的最终结束标志是:公式中差的平方和小于预先设定的值,则认为找到最优解了。可以看出,这个最优解不一定是全局最优的。
java源码如下:
package sparkTest; /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // $example on$ import scala.Tuple2; import org.apache.spark.api.java.*; import org.apache.spark.api.java.function.Function; import org.apache.spark.mllib.recommendation.ALS; import org.apache.spark.mllib.recommendation.MatrixFactorizationModel; import org.apache.spark.mllib.recommendation.Rating; import org.apache.spark.SparkConf; // $example off$ public class JavaRecommendationExample { public static void main(String args[]) { // $example on$ SparkConf conf = new SparkConf().setAppName("Java Collaborative Filtering Example").setMaster("local"); JavaSparkContext jsc = new JavaSparkContext(conf); // Load and parse the data String path = "input/test.data"; JavaRDD<String> data = jsc.textFile(path); JavaRDD<Rating> ratings = data.map(new Function<String, Rating>() { //Rating包含user、item、rating public Rating call(String s) { String[] sarray = s.split(","); return new Rating(Integer.parseInt(sarray[0]), Integer.parseInt(sarray[1]), Double.parseDouble(sarray[2])); } } ); // Build the recommendation model using ALS int rank = 10; int numIterations = 10; //MatrixFactorizationModel:矩阵因式分解模型 //toRDD:JavaRDD转化为RDD /*train()参数详解 * RDD<ratings>:原始的评分矩阵 * rank:模型中隐语义因子个数 * iterations:迭代次数 * lambda:正则化参数,防止过度拟合 */ MatrixFactorizationModel model = ALS.train(JavaRDD.toRDD(ratings), rank, numIterations, 0.01); // Evaluate the model on rating data /*map()参数详解 * rating.user() * rating.product() * 返回新的JavaRDD:包含user, product */ JavaRDD<Tuple2<Object, Object>> userProducts = ratings.map(new Function<Rating, Tuple2<Object, Object>>() { public Tuple2<Object, Object> call(Rating r) { return new Tuple2<Object, Object>(r.user(), r.product()); } } ); //预测 /*model.predict():对user,product的评分进行预测 * RDD:从JavaRDD转化过来的RDD * 返回RDD<Rating> */ /*RDD<Rating>.toJavaRDD()转化为JavaRDD,便于后面的map */ JavaPairRDD<Tuple2<Integer, Integer>, Double> predictions = JavaPairRDD.fromJavaRDD( model.predict(JavaRDD.toRDD(userProducts)).toJavaRDD().map(new Function<Rating, Tuple2<Tuple2<Integer, Integer>, Double>>() { public Tuple2<Tuple2<Integer, Integer>, Double> call(Rating r){ return new Tuple2<Tuple2<Integer, Integer>, Double>( new Tuple2<Integer, Integer>(r.user(), r.product()), r.rating()); } } )); /*JavaPairRDD.fromJavaRDD():将JavaRDD(具有KeyValue形式)转化为JavaPairRDD * JavaPairRDD.join(JavaPairRDD other)将本RDD和other RDD中所有相同keys值的连接起来 * 换句话:将同一用户对同一商品的评价和预测值,连接起来 * JavaRDD.values()返回keyvalue键值对的value值 */ JavaRDD<Tuple2<Double, Double>> ratesAndPreds = JavaPairRDD.fromJavaRDD(ratings.map(new Function<Rating, Tuple2<Tuple2<Integer, Integer>, Double>>() { public Tuple2<Tuple2<Integer, Integer>, Double> call(Rating r){ return new Tuple2<Tuple2<Integer, Integer>, Double>( new Tuple2<Integer, Integer>(r.user(), r.product()), r.rating()); } } )).join(predictions).values(); /*JavaDoubleRDD.fromRDD()将RDD转化为Double类型的RDD * Function()求预测打分与真实打分之间的误差平方 * rdd()将JavaRDD转化为rdd * means()求JavaDoubleRDD中所有元素均值 */ double MSE = JavaDoubleRDD.fromRDD(ratesAndPreds.map(new Function<Tuple2<Double, Double>, Object>() { public Object call(Tuple2<Double, Double> pair) { Double err = pair._1() - pair._2(); return err * err; } } ).rdd()).mean(); System.out.println("Mean Squared Error = " + MSE); //打印均值 /*其实推荐系统还没完成 * 因为完成这个均方误差,无法直观得出该推荐什么元素给用户啊 *我们还需要从这个已经填满(预测出评分值)的矩阵中,找到适合推荐给某用户的商品,或者适合某商品的用户 *相应的函数为:model.recommendProducts(user, num); *model.recommendUsers(product, num); */ // Save and load model //save()将模型存储在指定位置,存储的结果可以在下次读取时,直接执行上面的推荐函数,给出推荐结果。 model.save(jsc.sc(), "target/tmp/myCollaborativeFilter"); MatrixFactorizationModel sameModel = MatrixFactorizationModel.load(jsc.sc(), "target/tmp/myCollaborativeFilter"); // $example off$ } }
注意:
各种模型的选择,比如MatrixFactorizationModel(矩阵分解模型)、FactorizationModel(分解模型) 以及 LinearRegressionModel(线性回归模型) 都支持评分预测。
参考文章3.
参考文章:
1、http://www.tuicool.com/articles/fANvieZ
2、http://www.mamicode.com/info-detail-865258.html
3、http://blog.jobbole.com/86959/
4、http://blog.sina.com.cn/s/blog_5773f1390102w2zr.html(一个电影推荐系统实例+代码)