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(一個電影推薦系統實例+代碼)