Added support for different Interpolation and Neighbout Search Algorithms
Added support for different Interpolation and Neighbout Search Algorithms
This commit is contained in:
@@ -25,6 +25,15 @@
|
||||
#include <mlpack/methods/cf/decomposition_policies/bias_svd_method.hpp>
|
||||
#include <mlpack/methods/cf/decomposition_policies/svdplusplus_method.hpp>
|
||||
|
||||
#include <mlpack/methods/cf/interpolation_policies/average_interpolation.hpp>
|
||||
#include <mlpack/methods/cf/interpolation_policies/regression_interpolation.hpp>
|
||||
#include <mlpack/methods/cf/interpolation_policies/similarity_interpolation.hpp>
|
||||
|
||||
#include <mlpack/methods/cf/neighbor_search_policies/cosine_search.hpp>
|
||||
#include <mlpack/methods/cf/neighbor_search_policies/lmetric_search.hpp>
|
||||
#include <mlpack/methods/cf/neighbor_search_policies/pearson_search.hpp>
|
||||
|
||||
|
||||
using namespace mlpack;
|
||||
using namespace mlpack::cf;
|
||||
using namespace mlpack::amf;
|
||||
@@ -125,10 +134,21 @@ PARAM_INT_IN("recommendations", "Number of recommendations to generate for each"
|
||||
|
||||
PARAM_INT_IN("seed", "Set the random seed (0 uses std::time(NULL)).", "s", 0);
|
||||
|
||||
// Interpolation and Neighbour Search Algorithms
|
||||
PARAM_STRING_IN("interpolation", "Algorithm used for weight interpolation.", "i",
|
||||
"Average");
|
||||
|
||||
PARAM_STRING_IN("neighbour_search", "Algorithm used for neighbour search.", "f",
|
||||
"Euclidean");
|
||||
|
||||
void ComputeRecommendations(CFModel* cf,
|
||||
const size_t numRecs,
|
||||
arma::Mat<size_t>& recommendations)
|
||||
{
|
||||
|
||||
const string ns_algo = CLI::GetParam<string>("neighbour_search");
|
||||
const string iw_algo = CLI::GetParam<string>("interpolation");
|
||||
|
||||
// Reading users.
|
||||
if (CLI::HasParam("query"))
|
||||
{
|
||||
@@ -142,17 +162,112 @@ void ComputeRecommendations(CFModel* cf,
|
||||
|
||||
Log::Info << "Generating recommendations for " << users.n_elem << " users."
|
||||
<< endl;
|
||||
cf->GetRecommendations(numRecs, recommendations, users.row(0).t());
|
||||
|
||||
// Making All the possible paths
|
||||
if(ns_algo=="Cosine")
|
||||
{
|
||||
if(iw_algo=="Average")
|
||||
{
|
||||
cf->GetRecommendations<CosineSearch,AverageInterpolation>(numRecs, recommendations, users.row(0).t());
|
||||
}
|
||||
else if(iw_algo=="Regression")
|
||||
{
|
||||
cf->GetRecommendations<CosineSearch,RegressionInterpolation>(numRecs, recommendations, users.row(0).t());
|
||||
}
|
||||
else if(iw_algo=="Similarity")
|
||||
{
|
||||
cf->GetRecommendations<CosineSearch,SimilarityInterpolation>(numRecs, recommendations, users.row(0).t());
|
||||
}
|
||||
}
|
||||
else if(ns_algo=="Euclidean")
|
||||
{
|
||||
if(iw_algo=="Average")
|
||||
{
|
||||
cf->GetRecommendations<EuclideanSearch,AverageInterpolation>(numRecs, recommendations, users.row(0).t());
|
||||
}
|
||||
else if(iw_algo=="Regression")
|
||||
{
|
||||
cf->GetRecommendations<EuclideanSearch,RegressionInterpolation>(numRecs, recommendations, users.row(0).t());
|
||||
}
|
||||
else if(iw_algo=="Similarity")
|
||||
{
|
||||
cf->GetRecommendations<EuclideanSearch,SimilarityInterpolation>(numRecs, recommendations, users.row(0).t());
|
||||
}
|
||||
}
|
||||
else if(ns_algo=="Pearson")
|
||||
{
|
||||
if(iw_algo=="Average")
|
||||
{
|
||||
cf->GetRecommendations<PearsonSearch,AverageInterpolation>(numRecs, recommendations, users.row(0).t());
|
||||
}
|
||||
else if(iw_algo=="Regression")
|
||||
{
|
||||
cf->GetRecommendations<PearsonSearch,RegressionInterpolation>(numRecs, recommendations, users.row(0).t());
|
||||
}
|
||||
else if(iw_algo=="Similarity")
|
||||
{
|
||||
cf->GetRecommendations<PearsonSearch,SimilarityInterpolation>(numRecs, recommendations, users.row(0).t());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info << "Generating recommendations for all users." << endl;
|
||||
cf->GetRecommendations(numRecs, recommendations);
|
||||
if(ns_algo=="Cosine")
|
||||
{
|
||||
if(iw_algo=="Average")
|
||||
{
|
||||
cf->GetRecommendations<CosineSearch,AverageInterpolation>(numRecs, recommendations);
|
||||
}
|
||||
else if(iw_algo=="Regression")
|
||||
{
|
||||
cf->GetRecommendations<CosineSearch,RegressionInterpolation>(numRecs, recommendations);
|
||||
}
|
||||
else if(iw_algo=="Similarity")
|
||||
{
|
||||
cf->GetRecommendations<CosineSearch,SimilarityInterpolation>(numRecs, recommendations);
|
||||
}
|
||||
}
|
||||
else if(ns_algo=="Euclidean")
|
||||
{
|
||||
if(iw_algo=="Average")
|
||||
{
|
||||
cf->GetRecommendations<EuclideanSearch,AverageInterpolation>(numRecs, recommendations);
|
||||
}
|
||||
else if(iw_algo=="Regression")
|
||||
{
|
||||
cf->GetRecommendations<EuclideanSearch,RegressionInterpolation>(numRecs, recommendations);
|
||||
}
|
||||
else if(iw_algo=="Similarity")
|
||||
{
|
||||
cf->GetRecommendations<EuclideanSearch,SimilarityInterpolation>(numRecs, recommendations);
|
||||
}
|
||||
}
|
||||
else if(ns_algo=="Pearson")
|
||||
{
|
||||
if(iw_algo=="Average")
|
||||
{
|
||||
cf->GetRecommendations<PearsonSearch,AverageInterpolation>(numRecs, recommendations);
|
||||
}
|
||||
else if(iw_algo=="Regression")
|
||||
{
|
||||
cf->GetRecommendations<PearsonSearch,RegressionInterpolation>(numRecs, recommendations);
|
||||
}
|
||||
else if(iw_algo=="Similarity")
|
||||
{
|
||||
cf->GetRecommendations<PearsonSearch,SimilarityInterpolation>(numRecs, recommendations);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ComputeRMSE(CFModel* cf)
|
||||
{
|
||||
// Interpolation and Neighbour Search
|
||||
|
||||
const string ns_algo = CLI::GetParam<string>("neighbour_search");
|
||||
const string iw_algo = CLI::GetParam<string>("interpolation");
|
||||
|
||||
// Now, compute each test point.
|
||||
arma::mat testData = std::move(CLI::GetParam<arma::mat>("test"));
|
||||
|
||||
@@ -166,7 +281,52 @@ void ComputeRMSE(CFModel* cf)
|
||||
|
||||
// Now compute the RMSE.
|
||||
arma::vec predictions;
|
||||
cf->Predict(combinations, predictions);
|
||||
|
||||
if(ns_algo=="Cosine")
|
||||
{
|
||||
if(iw_algo=="Average")
|
||||
{
|
||||
cf->Predict<CosineSearch,AverageInterpolation>(combinations, predictions);
|
||||
}
|
||||
else if(iw_algo=="Regression")
|
||||
{
|
||||
cf->Predict<CosineSearch,RegressionInterpolation>(combinations, predictions);
|
||||
}
|
||||
else if(iw_algo=="Similarity")
|
||||
{
|
||||
cf->Predict<CosineSearch,SimilarityInterpolation>(combinations, predictions);
|
||||
}
|
||||
}
|
||||
else if(ns_algo=="Euclidean")
|
||||
{
|
||||
if(iw_algo=="Average")
|
||||
{
|
||||
cf->Predict<EuclideanSearch,AverageInterpolation>(combinations, predictions);
|
||||
}
|
||||
else if(iw_algo=="Regression")
|
||||
{
|
||||
cf->Predict<EuclideanSearch,RegressionInterpolation>(combinations, predictions);
|
||||
}
|
||||
else if(iw_algo=="Similarity")
|
||||
{
|
||||
cf->Predict<EuclideanSearch,SimilarityInterpolation>(combinations, predictions);
|
||||
}
|
||||
}
|
||||
else if(ns_algo=="Pearson")
|
||||
{
|
||||
if(iw_algo=="Average")
|
||||
{
|
||||
cf->Predict<PearsonSearch,AverageInterpolation>(combinations, predictions);
|
||||
}
|
||||
else if(iw_algo=="Regression")
|
||||
{
|
||||
cf->Predict<PearsonSearch,RegressionInterpolation>(combinations, predictions);
|
||||
}
|
||||
else if(iw_algo=="Similarity")
|
||||
{
|
||||
cf->Predict<PearsonSearch,SimilarityInterpolation>(combinations, predictions);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the root of the sum of the squared errors, divide by the number of
|
||||
// points to get the RMSE. It turns out this is just the L2-norm divided by
|
||||
@@ -287,6 +447,13 @@ static void mlpackMain()
|
||||
"SVDIncompleteIncremental", "SVDCompleteIncremental", "RegSVD",
|
||||
"RandSVD", "BiasSVD", "SVDPP" }, true, "unknown algorithm");
|
||||
|
||||
// Validate the interpolation and neighbour_search policy
|
||||
RequireParamInSet<string>("interpolation", { "Average", "Regression", "Similarity" },
|
||||
true, "unknown interpolation algorithm");
|
||||
|
||||
RequireParamInSet<string>("neighbour_search", { "Cosine", "Euclidean", "Pearson" },
|
||||
true, "unknown neighbour search algorithm");
|
||||
|
||||
ReportIgnoredParam({{ "iteration_only_termination", true }}, "min_residue");
|
||||
|
||||
RequireParamValue<int>("recommendations", [](int x) { return x > 0; }, true,
|
||||
|
||||
@@ -54,6 +54,8 @@ class GetValueVisitor : public boost::static_visitor<void*>
|
||||
* PredictVisitor uses the CFType object to make predictions on the given
|
||||
* combinations of users and items.
|
||||
*/
|
||||
template <typename NeighbourSearchPolicy,
|
||||
typename InterpolationPolicy>
|
||||
class PredictVisitor : public boost::static_visitor<void>
|
||||
{
|
||||
private:
|
||||
@@ -76,6 +78,8 @@ class PredictVisitor : public boost::static_visitor<void>
|
||||
* RecommendationVisitor uses the CFType object to get recommendations for the
|
||||
* given users.
|
||||
*/
|
||||
template <typename NeighbourSearchPolicy,
|
||||
typename InterpolationPolicy>
|
||||
class RecommendationVisitor : public boost::static_visitor<void>
|
||||
{
|
||||
private:
|
||||
@@ -142,15 +146,21 @@ class CFModel
|
||||
const bool mit);
|
||||
|
||||
//! Make predictions.
|
||||
template <typename NeighbourSearchPolicy,
|
||||
typename InterpolationPolicy>
|
||||
void Predict(const arma::Mat<size_t>& combinations,
|
||||
arma::vec& predictions);
|
||||
|
||||
//! Compute recommendations for query users.
|
||||
template<typename NeighbourSearchPolicy,
|
||||
typename InterpolationPolicy>
|
||||
void GetRecommendations(const size_t numRecs,
|
||||
arma::Mat<size_t>& recommendations,
|
||||
const arma::Col<size_t>& users);
|
||||
|
||||
//! Compute recommendations for all users.
|
||||
template<typename NeighbourSearchPolicy,
|
||||
typename InterpolationPolicy>
|
||||
void GetRecommendations(const size_t numRecs,
|
||||
arma::Mat<size_t>& recommendations);
|
||||
|
||||
|
||||
@@ -34,15 +34,19 @@ void* GetValueVisitor::operator()(CFType<DecompositionPolicy>* c) const
|
||||
return (void*) c;
|
||||
}
|
||||
|
||||
PredictVisitor::PredictVisitor(
|
||||
template <typename NeighbourSearchPolicy,
|
||||
typename InterpolationPolicy>
|
||||
PredictVisitor<NeighbourSearchPolicy,InterpolationPolicy>::PredictVisitor(
|
||||
const arma::Mat<size_t>& combinations,
|
||||
arma::vec& predictions) :
|
||||
combinations(combinations),
|
||||
predictions(predictions)
|
||||
{ }
|
||||
|
||||
template <typename NeighbourSearchPolicy,
|
||||
typename InterpolationPolicy>
|
||||
template<typename DecompositionPolicy>
|
||||
void PredictVisitor::operator()(CFType<DecompositionPolicy>* c) const
|
||||
void PredictVisitor<NeighbourSearchPolicy,InterpolationPolicy>::operator()(CFType<DecompositionPolicy>* c) const
|
||||
{
|
||||
if (!c)
|
||||
{
|
||||
@@ -50,10 +54,13 @@ void PredictVisitor::operator()(CFType<DecompositionPolicy>* c) const
|
||||
return;
|
||||
}
|
||||
|
||||
c->Predict(combinations, predictions);
|
||||
c->template Predict<NeighbourSearchPolicy,InterpolationPolicy>(combinations, predictions);
|
||||
}
|
||||
|
||||
RecommendationVisitor::RecommendationVisitor(
|
||||
template <typename NeighbourSearchPolicy,
|
||||
typename InterpolationPolicy>
|
||||
RecommendationVisitor<NeighbourSearchPolicy,InterpolationPolicy>
|
||||
::RecommendationVisitor(
|
||||
const size_t numRecs,
|
||||
arma::Mat<size_t>& recommendations,
|
||||
const arma::Col<size_t>& users,
|
||||
@@ -64,8 +71,11 @@ RecommendationVisitor::RecommendationVisitor(
|
||||
usersGiven(usersGiven)
|
||||
{ }
|
||||
|
||||
template <typename NeighbourSearchPolicy,
|
||||
typename InterpolationPolicy>
|
||||
template<typename DecompositionPolicy>
|
||||
void RecommendationVisitor::operator()(CFType<DecompositionPolicy>* c) const
|
||||
void RecommendationVisitor<NeighbourSearchPolicy,InterpolationPolicy>
|
||||
::operator()(CFType<DecompositionPolicy>* c) const
|
||||
{
|
||||
if (!c)
|
||||
{
|
||||
@@ -74,9 +84,9 @@ void RecommendationVisitor::operator()(CFType<DecompositionPolicy>* c) const
|
||||
}
|
||||
|
||||
if (usersGiven)
|
||||
c->GetRecommendations(numRecs, recommendations, users);
|
||||
c->template GetRecommendations<NeighbourSearchPolicy,InterpolationPolicy>(numRecs, recommendations, users);
|
||||
else
|
||||
c->GetRecommendations(numRecs, recommendations);
|
||||
c->template GetRecommendations<NeighbourSearchPolicy,InterpolationPolicy>(numRecs, recommendations);
|
||||
}
|
||||
|
||||
CFModel::~CFModel()
|
||||
@@ -103,28 +113,34 @@ void CFModel::Train(const MatType& data,
|
||||
}
|
||||
|
||||
//! Make predictions.
|
||||
template <typename NeighbourSearchPolicy,
|
||||
typename InterpolationPolicy>
|
||||
void CFModel::Predict(const arma::Mat<size_t>& combinations,
|
||||
arma::vec& predictions)
|
||||
{
|
||||
PredictVisitor predict(combinations, predictions);
|
||||
PredictVisitor<NeighbourSearchPolicy,InterpolationPolicy> predict(combinations, predictions);
|
||||
boost::apply_visitor(predict, cf);
|
||||
}
|
||||
|
||||
//! Compute recommendations for queried users.
|
||||
template<typename NeighbourSearchPolicy,
|
||||
typename InterpolationPolicy>
|
||||
void CFModel::GetRecommendations(const size_t numRecs,
|
||||
arma::Mat<size_t>& recommendations,
|
||||
const arma::Col<size_t>& users)
|
||||
{
|
||||
RecommendationVisitor recommendation(numRecs, recommendations, users, true);
|
||||
RecommendationVisitor<NeighbourSearchPolicy,InterpolationPolicy> recommendation(numRecs, recommendations, users, true);
|
||||
boost::apply_visitor(recommendation, cf);
|
||||
}
|
||||
|
||||
//! Compute recommendations for all users.
|
||||
template<typename NeighbourSearchPolicy,
|
||||
typename InterpolationPolicy>
|
||||
void CFModel::GetRecommendations(const size_t numRecs,
|
||||
arma::Mat<size_t>& recommendations)
|
||||
{
|
||||
arma::Col<size_t> users;
|
||||
RecommendationVisitor recommendation(numRecs, recommendations, users, false);
|
||||
RecommendationVisitor<NeighbourSearchPolicy,InterpolationPolicy> recommendation(numRecs, recommendations, users, false);
|
||||
boost::apply_visitor(recommendation, cf);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user