Slope One 是一种很简单的类比类似的算法, 其实大体意思 就是A B 不同的用户 对不同的 item1 item2 打分
那么 一个新用户C 对item的打分,就是 该用户的打分 减去 其他用户打分的平均 就是C用户对未知tem的打分
他有个很好的有点,数据少的时候效果也很好。
user | item1 | item2 |
A | 7 | 2 |
B | 8 | 3 |
C | 9 |
那么 C的item2 打分 为 9-((7-2)+(8-3))/2=4
其实分成2步
1. 计算物品之间评分差的平均值,记为物品间的评分偏差;
2.根据物品间的评分偏差和用户的历史评分,给用户生成预测评分高的推荐物品列表。
算法 很简单吧,使用spark 读取DataFrame 对列 进行上面的算法 map 运算 reduce运算 就可以了 ,然后写入数据库。
就得到slope One的评分 其实本质 就是y=wx+b 的线性回归问题,
OK 想到了吧。其实 spark 如果自己 写一个slope one 算法 也是可以的
但是 这些完全没必要 直接 使用线性回归模型 就可以了对位置字段抽离 new LinearRegressionWithSGD()
一样可以做到slope one的效果。
如果我们自己写一个slope one怎么做了
data--- map--->(user,uid)---->map key ----> (user ratings)--->values--->(user,(item1,item2))--->reduce user ---->(user,ratingsum/count)
第一步 1.便利所有的用户 并 便利所有的用户下面 分别计算 item 之间的评分之间的差相加
第二步 便利用户的item 然后利用上面计算的矩阵 同上 求得 评分
详细的代码 可以看
这是python 实现的代码。
最后的最后,不说虚的 放一个彩蛋 。。。。。 不是像网上说了一大堆,只是算法的讲解 ,并没有怎么使用的 文章,这里放出一个spark 的实现,本人使用过,其实我根本实际不会用slope One 我做数据推荐 方法 多的是,最差的都比slope one 要好,后面会讲到 这里我只是补充简单的方式,也指出一下。
我是把下面的scala 代码全部改成java的了。。其实个人一直觉得 spark 开发 一定需要scala吗,有什么不同最后都是编译成class 文件,spark 用scala 写的 但是最后的jar包 不都是class 文件,也就是遵循java语法,我难道不可以直接调用吗,最复杂的无非就是ClassTag 但是classTag,$. 可以把java对象转为ClassTag 对象 ,所以 其实scala 写的代码 java 可以无缝调用,也就是说 你可以写 spark代码 纯java代码 一模一样的,最后都是编译成class 文件,交给jvm调用,都是java规范,都是最后编译成java代码 ,所以没有区别,我不太喜欢scala 除了看是简洁 没有什么实际用处,想法 python 语言 就足够强大 ,如果可以的大家 可以学学python 以后人工智能 机器学习 离不开它。 其实我特别不认同 spark 需要scala来写,大家尽管全部用java来写,一样的,spark 第三方的216个扩展包,我数了好几遍 ,其中 198个都是纯java代码写的 。。。无论是深度学习
还是 机器学习算法 还是各类的扩展 来源 写入,所有代码 都是java写的。所以尽管放心,无非就是classTag 这个定义一个静态方法 封装 就可以了 ,其他的就是想普通java 开发即可 。在我看来 用scala 来写 就是装个逼而已,你用java来写 最后打成的jar 包有什么不同。
import scala.collection.mutable.HashMapobject SlopeOne { var mData = new HashMap[Int, HashMap[Int, Double]]() var mDiffMatrix = new HashMap[Int, HashMap[Int, Double]]() var mFreqMatrix = new HashMap[Int, HashMap[Int, Int]]() var mAllItems = Array[Int]() def buildit(file: String) { // val buff = Source.fromFile(new File(file)) // buff.getLines.toArray.map(line => { // val arr = line.split(" ") // val iid = arr(1).toInt - 1 // val uid = arr(0).toInt - 1 // val sc = arr(2).toDouble // if (!mData.contains(uid)) { // mData(uid) = new HashMap[Int, Double]() // } // mData(uid) += ((iid, sc)) // }) // buff.close mData.map(user => { val user2 = user._2 val user3 = user._2 println("User" + user._1) user2.map(entry => { val item = entry._1 val score = entry._2 if (!mDiffMatrix.contains(item)) { mDiffMatrix(item) = new HashMap[Int, Double]() mFreqMatrix(item) = new HashMap[Int, Int]() } user3.map(entry2 => { val item2 = entry2._1 val score2 = entry2._2 var oldcount = 0; if (mFreqMatrix(item).contains(item2)) oldcount = mFreqMatrix(item)(item2) var olddiff = 0.0 if (mDiffMatrix(item).contains(item2)) olddiff = mDiffMatrix(item)(item2) val observeddiff = score - score2 mFreqMatrix(item).put(item2, oldcount + 1) mDiffMatrix(item).put(item2, olddiff + observeddiff) }) }) }) mDiffMatrix.map(item => { val j = item._1 item._2.map(t => { val i = t._1 val oldvalue = mDiffMatrix(j)(i) val count = mFreqMatrix(j)(i) mDiffMatrix(j).put(i, oldvalue / count) }) }) } def predict(user: HashMap[Int, Double]): HashMap[Int, Double] = { var predictions = new HashMap[Int, Double]() var frequencies = new HashMap[Int, Int]() for (j <- mDiffMatrix.keys) { frequencies.put(j, 0); predictions.put(j, 0.0); } for (j <- user.keys) { for (k <- mDiffMatrix.keys) { try { val newval = (mDiffMatrix(k)(j) + user(j)) * mFreqMatrix(k)(j) predictions.put(k, predictions(k) + newval) frequencies.put(k, frequencies(k) + mFreqMatrix(k)(j)) } catch { case ex: Exception => {} } } } var cleanpredictions = new HashMap[Int, Double]() for (j <- predictions.keys) { if (frequencies(j) > 0) { cleanpredictions.put(j, predictions(j) / frequencies(j)) } } for (j <- user.keys) { cleanpredictions.put(j, user(j)) } cleanpredictions } def weightlesspredict(user: HashMap[Int, Double]): HashMap[Int, Double] = { var predictions = new HashMap[Int, Double]() var frequencies = new HashMap[Int, Int]() for (j <- mDiffMatrix.keys) { frequencies.put(j, 0); predictions.put(j, 0.0); } for (j <- user.keys) { for (k <- mDiffMatrix.keys) { //try { val newval = (mDiffMatrix(k)(j) + user(j)) //* mFreqMatrix(k)(j) predictions.put(k, predictions(k) + newval) //frequencies.put(k, frequencies(k)+mFreqMatrix(k)(j)) //} catch(NullPointerException e) {} } } for (j <- predictions.keys) { predictions.put(j, predictions(j) / user.size) } for (j <- user.keys) { predictions.put(j, user(j)); } predictions } def printData() { for (user <- mData.keys) { System.out.println(user); print(mData(user)); } for (i <- 0 until mAllItems.length) { System.out.print("\n" + mAllItems(i) + ":"); printMatrixes(mDiffMatrix(mAllItems(i)), mFreqMatrix(mAllItems(i))); } } def printMatrixes(ratings: HashMap[Int, Double], frequencies: HashMap[Int, Int]) { for (j <- 0 until mAllItems.length) { System.out.format("%10.3f", ratings.get(mAllItems(j))); System.out.print(" "); System.out.format("%10d", frequencies.get(mAllItems(j))); } System.out.println(); } def print(user: HashMap[Int, Double]) { for (j <- user.keys) { System.out.println(" " + j + " --> " + user(j)) } } def main(args: Array[String]): Unit = { var data = new HashMap[Int, HashMap[Int, Double]](); // items val item1 = 1 val item2 = 2 val item3 = 3 val item4 = 4 val item5 = 5 mAllItems = Array(item1, item2, item3, item4, item5) //I'm going to fill it in var user1 = new HashMap[Int, Double](); var user2 = new HashMap[Int, Double](); var user3 = new HashMap[Int, Double](); var user4 = new HashMap[Int, Double](); user1.put(item1, 1.0f); user1.put(item2, 0.5f); user1.put(item4, 0.1f); data.put(11, user1); user2.put(item1, 1.0f); user2.put(item3, 0.5f); user2.put(item4, 0.2f); data.put(12, user2); user3.put(item1, 0.9f); user3.put(item2, 0.4f); user3.put(item3, 0.5f); user3.put(item4, 0.1f); data.put(13, user3); user4.put(item1, 0.1f); //user4.put(item2,0.4f); //user4.put(item3,0.5f); user4.put(item4, 1.0f); user4.put(item5, 0.4f); data.put(14, user4); mData = data buildit("c:/traning.txt") // then, I'm going to test it out... var user = new HashMap[Int, Double](); System.out.println("Ok, now we predict..."); user.put(item5, 0.4f); System.out.println("Inputting..."); SlopeOne.print(user); System.out.println("Getting..."); predict(user) SlopeOne.print(predict(user)); // user.put(item4, 0.2f); System.out.println("Inputting..."); SlopeOne.print(user); System.out.println("Getting..."); SlopeOne.print(predict(user)); }}
好了 大家 可以去使用一下 ,懒得转java代码 就把这个类scala编译成class 文件打包 然后直接像java一样使用吧。