spark中协同过滤算法分析

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 data = jsc.textFile(path);
    JavaRDD ratings = data.map(new Function() {	//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:原始的评分矩阵
     * 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> userProducts = ratings.map(new Function>() {
        public Tuple2 call(Rating r) {
          return new Tuple2(r.user(), r.product());
        }
      }
    );
    
    //预测
    /*model.predict():对user,product的评分进行预测
     * RDD:从JavaRDD转化过来的RDD
     * 返回RDD
     */
    /*RDD.toJavaRDD()转化为JavaRDD,便于后面的map
     */
    JavaPairRDD, Double> predictions = JavaPairRDD.fromJavaRDD(
      model.predict(JavaRDD.toRDD(userProducts)).toJavaRDD().map(new Function, Double>>() {
          public Tuple2, Double> call(Rating r){
            return new Tuple2, Double>(
              new Tuple2(r.user(), r.product()), r.rating());
          }
        }
      ));
    
    /*JavaPairRDD.fromJavaRDD():将JavaRDD(具有KeyValue形式)转化为JavaPairRDD
     * JavaPairRDD.join(JavaPairRDD other)将本RDD和other RDD中所有相同keys值的连接起来
     * 换句话:将同一用户对同一商品的评价和预测值,连接起来
     * JavaRDD.values()返回keyvalue键值对的value值
     */
    JavaRDD> ratesAndPreds =
      JavaPairRDD.fromJavaRDD(ratings.map(new Function, Double>>() {
          public Tuple2, Double> call(Rating r){
            return new Tuple2, Double>(
              new Tuple2(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, Object>() {
        public Object call(Tuple2 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(一个电影推荐系统实例+代码)

你可能感兴趣的:(spark,协同过滤,spark,协同过滤算法)