Added support for different Interpolation and Neighbout Search Algorithms

Added support for different Interpolation and Neighbout Search Algorithms
This commit is contained in:
AYESDIE
2018-10-23 18:04:46 +05:30
committed by GitHub
parent aab058a250
commit aa94bf7dc2
3 changed files with 206 additions and 13 deletions
+170 -3
View File
@@ -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,
+10
View File
@@ -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);
+26 -10
View File
@@ -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);
}