[mlpack-svn] r15881 - mlpack/trunk/src/mlpack/methods/cf

fastlab-svn at coffeetalk-1.cc.gatech.edu fastlab-svn at coffeetalk-1.cc.gatech.edu
Mon Sep 30 22:13:17 EDT 2013


Author: rcurtin
Date: Mon Sep 30 22:13:17 2013
New Revision: 15881

Log:
Refactor CalculateTopRecommendations(), including a complete overhaul of how
recommendations are actually calculated.  std::pair<> and std::map<> are often
quite slow, especially in that implementation.  This is faster.


Modified:
   mlpack/trunk/src/mlpack/methods/cf/cf.cpp
   mlpack/trunk/src/mlpack/methods/cf/cf.hpp

Modified: mlpack/trunk/src/mlpack/methods/cf/cf.cpp
==============================================================================
--- mlpack/trunk/src/mlpack/methods/cf/cf.cpp	(original)
+++ mlpack/trunk/src/mlpack/methods/cf/cf.cpp	Mon Sep 30 22:13:17 2013
@@ -206,47 +206,73 @@
   int recos = numRecs;
   if(averages.n_cols<numRecs)
     recos = averages.n_rows;
-  //Stores recommendations
-  arma::Mat<size_t> rec = arma::zeros<arma::Mat<size_t> >(recos,users.n_rows);
-  //Stores valid ratings for items by a user
-  arma::Col<double> tmp = arma::zeros<arma::Col<double> >(rating.n_cols,1);
-  //Maps the items to their ratings
-  std::map<double,size_t> tmpMap;
-  //Iterator for the Item-Rating Map
-  std::map<double,size_t>::reverse_iterator iter;
-  std::map<double,size_t>::iterator it;
-  //Keeps count of number of recommendations provided for a user
-  size_t count;
-  //Iterate for all users
-  for(size_t i=0;i<users.n_rows;i++)
+
+  // Generate recommendations for each query user by finding the maximum numRecs
+  // elements in the averages matrix.
+  recommendations.set_size(numRecs, users.n_elem);
+  arma::mat values(numRecs, users.n_elem);
+  values.fill(-DBL_MAX); // The smallest possible value.
+  for (size_t i = 0; i < users.n_elem; i++)
   {
-    count=0;
-    //Dot product between average rating and mask to dilute the ratings
-    // of the items that user i has already rated
-    tmp = averages.col(users(i)-1) % mask.col(users(i)-1);
-    //Mapping Rating to Items
-    for(size_t j=0;j<tmp.n_rows;j++)
-      if(tmp(j)>=0)
-        tmpMap.insert(std::pair<double,size_t>(tmp(j),j+1));
-    //Iterating over Item-Rating Map
-    for(iter=tmpMap.rbegin();iter!=tmpMap.rend();++iter)
+    // Look through the averages column corresponding to the current user.
+    for (size_t j = 0; j < averages.n_rows; ++j)
     {
-       //Saving recommendations to the recommendations table
-      rec(count,i) = (size_t)iter->second;
-      count++;
-      //break is desired number of recommendations are saved
-      if(count==numRecs)
-        break;
+      // Ensure that the user hasn't already rated the item.
+      if (cleanedData(j, users(i) - 1) != 0.0)
+        continue; // The user already rated the item.
+
+      // Is the estimated value better than the worst candidate?
+      const double value = averages(j, i);
+      if (value > values(values.n_rows - 1, i))
+      {
+        // It should be inserted.  Which position?
+        size_t insertPosition = values.n_rows - 1;
+        while (insertPosition > 0)
+        {
+          if (value <= values(insertPosition - 1, i))
+            break; // The current value is the right one.
+          insertPosition--;
+        }
+
+        // Now insert it into the list.
+        InsertNeighbor(i, insertPosition, j, value, recommendations, values);
+      }
     }
-    //Removing the items from the map
-    //note: Item 0 is just to maintain the consistency and it
-    //represents not recommendations were available
-    for(it=tmpMap.begin();it!=tmpMap.end();++it)
-      tmpMap.erase(it);
   }
-  //Saving to recommendations
-  recommendations = rec;
 }
 
+/**
+ * Helper function to insert a point into the recommendation matrices.
+ *
+ * @param queryIndex Index of point whose recommendations we are inserting into.
+ * @param pos Position in list to insert into.
+ * @param neighbor Index of item being inserted as a recommendation.
+ * @param value Value of recommendation.
+ */
+void CF::InsertNeighbor(const size_t queryIndex,
+                        const size_t pos,
+                        const size_t neighbor,
+                        const double value,
+                        arma::Mat<size_t>& recommendations,
+                        arma::mat& values) const
+{
+  // We only memmove() if there is actually a need to shift something.
+  if (pos < (recommendations.n_rows - 1))
+  {
+    const int len = (values.n_rows - 1) - pos;
+    memmove(values.colptr(queryIndex) + (pos + 1),
+        values.colptr(queryIndex) + pos,
+        sizeof(double) * len);
+    memmove(recommendations.colptr(queryIndex) + (pos + 1),
+        recommendations.colptr(queryIndex) + pos,
+        sizeof(size_t) * len);
+  }
+
+  // Now put the new information in the right index.
+  values(pos, queryIndex) = value;
+  recommendations(pos, queryIndex) = neighbor;
+}
+
+
 }; // namespace mlpack
 }; // namespace cf

Modified: mlpack/trunk/src/mlpack/methods/cf/cf.hpp
==============================================================================
--- mlpack/trunk/src/mlpack/methods/cf/cf.hpp	(original)
+++ mlpack/trunk/src/mlpack/methods/cf/cf.hpp	Mon Sep 30 22:13:17 2013
@@ -214,6 +214,22 @@
                                    arma::mat& averages,
                                    arma::Col<size_t>& users) const;
 
+  /**
+   * Helper function to insert a point into the recommendation matrices.
+   *
+   * @param queryIndex Index of point whose recommendations we are inserting
+   *     into.
+   * @param pos Position in list to insert into.
+   * @param neighbor Index of item being inserted as a recommendation.
+   * @param value Value of recommendation.
+   */
+   void InsertNeighbor(const size_t queryIndex,
+                       const size_t pos,
+                       const size_t neighbor,
+                       const double value,
+                       arma::Mat<size_t>& recommendations,
+                       arma::mat& values) const;
+
 }; // class CF
 
 }; // namespace cf



More information about the mlpack-svn mailing list