Fast Matrix Factorization for Online Recommendation with Implicit Feedback论文代码分析
1 數據結構
userCount:用戶數
itemCount:項目數
user_ratings:ArrayList<ArrayList>,
問:此處為什么要用二維數組?
答:第1維是用戶,第2維是用戶對所有項目的評分。
testRatings:ArrayList
問:此處為什么只用一維數組?
答:個人認為這個處理有問題,因為每個用戶有1-2個評分作為測試集,如果用一維數組,則數組的下標就不能和用戶id(userId)一一對應。
2 讀取評分:ReadRatings_HoldOneOut
步驟如下:
用戶0:
[<0,0,4.0,0>,<0,1,4.0,0>,…,<0,64,5.0,0>,<0,65,3.0,0>][<0,0,4.0,0>, <0,1,4.0,0>, \dots, <0,64,5.0,0>, <0,65,3.0,0>][<0,0,4.0,0>,<0,1,4.0,0>,…,<0,64,5.0,0>,<0,65,3.0,0>]
注:<userId, itemId, score, timestamp>,<0,0,4.0,0><0,0,4.0,0><0,0,4.0,0>可以解讀為用戶0對項目0在0時刻評分為4.0分。
用戶1:
[<1,0,5.0,0>,<1,66,4.0,0>,…,<1,192,1.0,0>,<1,193,5.0,0>][<1,0,5.0,0>, <1,66,4.0,0>, \dots, <1,192,1.0,0>, <1,193,5.0,0>][<1,0,5.0,0>,<1,66,4.0,0>,…,<1,192,1.0,0>,<1,193,5.0,0>]
用戶2:
[<2,0,5.0,0>,<2,194,5.0,0>,…,<2,202,5.0,0>,<2,203,5.0,0>][<2,0,5.0,0>, <2,194,5.0,0>, \dots, <2,202,5.0,0>, <2,203,5.0,0>][<2,0,5.0,0>,<2,194,5.0,0>,…,<2,202,5.0,0>,<2,203,5.0,0>]
[<0,65,3.0,0>,<0,64,5.0,0>,<1,193,5.0,0>,<1,192,1.0,0>,<2,203,5.0,0>,<2,202,5.0,0>,<3,278,5.0,0>,<3,277,4.0,0>,<4,290,4.0,0>,<4,289,5.0,0>,<5,328,2.0,0>,<5,327,5.0,0>,<6,394,4.0,0>,<6,393,5.0,0>,<7,406,5.0,0>,<7,405,2.0,0>,<8,420,3.0,0>,<8,419,3.0,0>,<9,482,5.0,0>,<9,481,4.0,0>,…][<0,65,3.0,0>, <0,64,5.0,0>, <1,193,5.0,0>, <1,192,1.0,0>, <2,203,5.0,0>, <2,202,5.0,0>, <3,278,5.0,0>, < 3,277,4.0,0>, <4,290,4.0,0>, <4,289,5.0,0>, <5,328,2.0,0>, <5,327,5.0,0>, <6,394,4.0,0>, <6,393,5.0,0>, <7,406,5.0,0>, <7,405,2.0,0>, <8,420,3.0,0>, <8,419,3.0,0>, <9,482,5.0,0>, <9,481,4.0,0>, \dots][<0,65,3.0,0>,<0,64,5.0,0>,<1,193,5.0,0>,<1,192,1.0,0>,<2,203,5.0,0>,<2,202,5.0,0>,<3,278,5.0,0>,<3,277,4.0,0>,<4,290,4.0,0>,<4,289,5.0,0>,<5,328,2.0,0>,<5,327,5.0,0>,<6,394,4.0,0>,<6,393,5.0,0>,<7,406,5.0,0>,<7,405,2.0,0>,<8,420,3.0,0>,<8,419,3.0,0>,<9,482,5.0,0>,<9,481,4.0,0>,…]
問:這種方式有問題沒有?
答:有,測試集由于是一個一維的列表,導致利用testRatings.get(u).itemId這個代碼來取數據的時候,u并不是指代某個用戶id,而是列表中某個位置的下標,容易誤解為用戶id和項目id不匹配。
上面的不匹配是由于下面的代碼導致的,由于每一個用戶將最后兩個評分加入到測試集,導致用戶id和列表的下標對應不上。
//if (i == ratings.size() - 1) { // test if (i == ratings.size() - 1 || i == ratings.size() - 2) { // testtestRatings.add(ratings.get(i));//the size of testing = the number of users. } else { // traintrainMatrix.setValue(userId, itemId, ratings.get(i).score); }//of if方案(1):改成如下代碼即可,使得每個用戶只有一個評分加入測試集,即測試集大小和用戶數一致
if (i == ratings.size() - 1) { // test //if (i == ratings.size() - 1 || i == ratings.size() - 2) { // testtestRatings.add(ratings.get(i));//the size of testing = the number of users. } else { // traintrainMatrix.setValue(userId, itemId, ratings.get(i).score); }//of if方案(2):可以用二維列表來存儲測試集。
3 evaluate_for_user的理解
3.1 數據結構
map_item_score:HashMap<Integer, Double>,散列表。HashMap的主干是一個Entry數組,Entry是HashMap的基本組成單元,每一個Entry包含一個key-value鍵值對。
HashMap<Integer, Double> map_item_score = new HashMap<Integer, Double>();ignoreSet:HashSet ,HashSet 基于 HashMap 來實現的,一個不允許有重復元素的集合。
3.2 代碼解讀
/*** Evaluation for a specific user with given GT item.對具有給定Groud-Truth項目的特定用戶的評估* @return:* result[0]: hit ratio* result[1]: ndcg* result[2]: precision*/protected double[] evaluate_for_user(int u, int gtItem) {double[] result = new double[3];HashMap<Integer, Double> map_item_score = new HashMap<Integer, Double>();// Get the score of the test item first.double maxScore = predict(u, gtItem);// Early stopping if there are topK items larger than maxScore.int countLarger = 0;for (int i = 0; i < itemCount; i++) {double score = predict(u, i);//預測用戶u對所有項目的評分map_item_score.put(i, score);//將預測評分放入散列表中,key為i,value為score//下面的兩句的作用是只要gtItem沒有進入TopK則不計算三個評價指標?if (score > maxScore) countLarger ++;if (countLarger > topK) return result; // early stopping}// Selecting topK items (does not exclude train items).ArrayList<Integer> rankList = ignoreTrain ? CommonUtils.TopKeysByValue(map_item_score, topK, trainMatrix.getRowRef(u).indexList()) : CommonUtils.TopKeysByValue(map_item_score, topK, null);result[0] = getHitRatio(rankList, gtItem);result[1] = getNDCG(rankList, gtItem);result[2] = getPrecision(rankList, gtItem);return result;}/*** Get the topK keys (by its value) of a map. Does not consider the keys which are in ignoreKeys.* @param map* @return*/public static<K, V extends Comparable<? super V>> ArrayList<K> TopKeysByValue(Map<K, V> map, int topK, ArrayList<K> ignoreKeys) {HashSet<K> ignoreSet;if (ignoreKeys == null) {ignoreSet = new HashSet<K>();} else {ignoreSet = new HashSet<K> (ignoreKeys);//將訓練集中用戶u購買過的項目放入ignoreSet}//因為map保存的是所有項目,如果要忽略訓練集中的項目,則將訓練集之外的項目寫入topQueueTopKPriorityQueue<K, V> topQueue = new TopKPriorityQueue<K, V>(topK);for (Map.Entry<K, V> entry : map.entrySet()) {if (!ignoreSet.contains(entry.getKey())) {topQueue.add(entry);}}//對topQueue中的元素進行排序,排序后保存在topKeys并返回ArrayList<K> topKeys = new ArrayList<K>();for (Map.Entry<K, V> entry : topQueue.sortedList()) {topKeys.add(entry.getKey());}return topKeys;}public ArrayList<Map.Entry<K, V>> sortedList() {ArrayList<Map.Entry<K, V>> list = new ArrayList<Map.Entry<K, V>>(queue); Collections.sort(list, c.reversed()); return list;}Collections.sort參考博客https://baijiahao.baidu.com/s?id=1660417080221659283&wfr=spider&for=pc
這里還用到了一個非常重要的接口Comparable。
功能: Comparable接口可用于對象的排序或者對象的分組
介紹: Comparable接口強行對實現它的類的每個實例進行自然排序,該接口的唯一方法compareTo方法被稱為自然比較方法
方法: int compareTo(Object o)
利用當前對象和傳入的目標對象進行比較:
- 若是當前對象比目標對象大,則返回1,那么當前對象會排在目標對象的后面
- 若是當前對象比目標對象小,則返回-1,那么當前對象會排在目標對象的后面
- 若是兩個對象相等,則返回0
總結
以上是生活随笔為你收集整理的Fast Matrix Factorization for Online Recommendation with Implicit Feedback论文代码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数学学习的心理——关于数学中的挫败的反思
- 下一篇: java 获取td_[Java教程]jQ