// Get Modified KNN Recommendations public Recommendation[] GetRecommendations_ModifiedKNN(int[] current_recipe, DistanceChoice distance_choice, Voting voting, ref int new_k) { MLContext ml = new MLContext(); DataManager dm = new DataManager(); int max_k = dm.GetRecipes(ModelChoice.KNN, DataPurpose.TEST).GroupBy(d => d.recipeId).ToArray().Length; Data[] train_data = dm.GetRecipes(ModelChoice.KNN, DataPurpose.TRAIN); string[] ingrNames = dm.GetFeatures(); // keep track of ingredient scores (recommendations) Recommendation[] recommendations = new Recommendation[ingrNames.Length]; for (int i = 0; i < ingrNames.Length; i++) { recommendations[i] = new Recommendation(new Ingredient(i, ingrNames[i]), 0.0); } // calculate all distances, find nearest neighbors to current recipe Neighbors[] distances = GetDistances(distance_choice, current_recipe, train_data, voting); recommendations = ModifiedKNN(recommendations, distances, current_recipe, ingrNames, ref new_k, max_k); // sort recommendations = recommendations.OrderByDescending(d => d.score).ToArray(); return(recommendations); }
// Get recommendations public Recommendation[] GetRecommendations(int k, DistanceChoice distance_choice, int[] recipe, Voting voting) { MLContext ml = new MLContext(); DataManager dm = new DataManager(); // get features (ingredient names) string[] ingrNames = dm.GetFeatures(); // get training recipes Data[] data = dm.GetRecipes(ModelChoice.KNN, DataPurpose.TRAIN); Recommendation[] recommendations = new Recommendation[ingrNames.Length]; // iterate through all ingredients for (int i = 0; i < ingrNames.Length; i++) { Ingredient current_ingr = new Ingredient(i, ingrNames[i]); // calculate all distances Neighbors[] distances = GetDistances(distance_choice, recipe, data, voting); double recommended = 0; double not_recommended = 0; // k nearest neighbors vote // recommend ingredient if the majority of neighbors contains the ingredient for (int top = 0; top < k; top++) { // recommend ingredient if (distances[top].recipe.Contains(i)) { if (voting.Equals(Voting.Unweighted)) { recommended++; } else { recommended += distances[top].distance; } } // do not recommend ingredient else { if (voting.Equals(Voting.Unweighted)) { not_recommended++; } else { not_recommended += distances[top].distance; } } } recommendations[i] = new Recommendation(current_ingr, (recommended + 1.0) / (not_recommended + 2.0)); } recommendations = recommendations.OrderByDescending(r => r.score).ToArray(); return(recommendations); }
// Get recommendations for a recipe // the ingredient score is equivalent to the posterior public Recommendation[] RecipeRecommendations(double[][] model, int[] recipe, bool laplace, bool normalize, bool prior) { MLContext ml = new MLContext(); DataManager dm = new DataManager(); // get features (unique ingredients) string[] ingr_names = dm.GetFeatures(); // get number of training recipes IDataView allrecipes = dm.GetDataView(ModelChoice.NB, ml, DataPurpose.TRAIN); int num_recipes = allrecipes.GetColumn <int>(allrecipes.Schema["recipeId"]).ToArray().Length; Recommendation[] recommendations = new Recommendation[ingr_names.Length]; // iterate through all features (unique ingredients) for (int f = 0; f < ingr_names.Length; f++) { double likelihood = 1.0; // iterate through all the ingredients in the recipe foreach (int i in recipe) { // ignore matching ingredients if (i != f) { // laplace smoothing if (laplace == true) { likelihood *= (model[i][f] + 1.0) / (model[f][f] + ingr_names.Length); } else { likelihood *= model[i][f] / model[f][f]; } // normalize if (normalize == true) { likelihood /= model[i][i]; } } } // prior if (prior == true) { likelihood *= model[f][f] / num_recipes; } recommendations[f] = new Recommendation(new Ingredient(f, ingr_names[f]), likelihood); } // sort recommendations = recommendations.OrderByDescending(t => t.score).ToArray(); return(recommendations); }
// Evaluate Non-negative Matrix Factorization public void EvaluateNMF(ITransformer model) { Console.WriteLine("\nEvaluating NMF..."); MLContext mlContext = new MLContext(); // get test data DataManager dm = new DataManager(); // test data IDataView testData = dm.GetDataView(ModelChoice.NMF, mlContext, DataPurpose.TEST); Data[] test_data = dm.GetRecipes(ModelChoice.NMF, DataPurpose.TEST); // train data IDataView trainData = dm.GetDataView(ModelChoice.NMF, mlContext, DataPurpose.TRAIN); Data[] train_data = dm.GetRecipes(ModelChoice.NMF, DataPurpose.TRAIN); // features string[] features = dm.GetFeatures(); int[] recipeArray = testData.GetColumn <int>(testData.Schema["recipeId"]).ToArray(); Results results = new Results(0); Recommender recommender = new Recommender(); // distinct test recipes int[] distinct_recipes = recipeArray.Distinct().ToArray(); // for each test recipe foreach (int r in distinct_recipes) { Recommendation[] recommendations = new Recommendation[features.Length]; Data[] recipe = test_data.Where(d => d.recipeId == r && d.score == 1).ToArray(); Data[] trecipe = train_data.Where(d => d.recipeId == r && d.score == 1).ToArray(); // get recipe r Data[] combined = recipe.Concat(trecipe).ToArray(); int[] current_recipe = dm.GetRecipe(combined.ToArray()); // iterate through all features for (int i = 0; i < dm.GetFeatures().Length; i++) { // make prediction (get score) double prediction = recommender.SinglePrediction(mlContext, model, i, r); // save score of ingredient recommendations[i] = new Recommendation(new Ingredient(i, features[i]), prediction); } // sort recommendations = recommendations.OrderByDescending(d => d.score).ToArray(); results = GetResults(results, recommendations, current_recipe); } // Display accuracy results results.ShowResults(); Console.WriteLine(); }