Commit 6f60e751 authored by Lorenzo Trujillo Rojas's avatar Lorenzo Trujillo Rojas
Browse files

Se creó un algoritmo para recomendación de lugares

parent 9d04cd7c
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
import { RecommendPlace } from '../dto/recommend-route.dto';
import { DataFrame, Series } from './math';
import { customSort } from './sort';

export class RecommendationsSystem {
  getCategories(places: RecommendPlace[]): number[] {
    const categories = new Set<number>();
    for (const place of places) {
      for (const category of place.categories) {
        categories.add(category);
      }
    }
    return Array.from(categories);
  }

  oneHotEncode(categories: number[], placesToEncode: RecommendPlace[]): DataFrame {
    const data: DataFrame = {};
    for (const category of categories) {
      data[category] = [];
      for (const place of placesToEncode) {
        data[category].push(place.categories.includes(category) ? 1 : 0);
      }
    }
    return data;
  }

  rankVisited(visited: RecommendPlace[]): Series {
    const visitedCategories = this.getCategories(visited);
    const visitedEncoded = this.oneHotEncode(visitedCategories, visited);
    const grades = visited.map((place) => place.grade);

    const dataframe: DataFrame = visitedEncoded;

    const result: Series = {};
    for (const category in dataframe) {
      result[category] = dataframe[category].reduce((sum, value, index) => sum + value * grades[index], 0);
    }

    const sumResult = Object.values(result).reduce((a, b) => a + b, 0);
    for (const category in result) {
      result[category] /= sumResult;
    }

    return result;
  }

  rankCandidates(candidates: RecommendPlace[], visited: Series): [number, number][] {
    const visitedCategories = Object.keys(visited).map(Number);
    const candidatesEncoded = this.oneHotEncode(visitedCategories, candidates);

    const dataframe: DataFrame = candidatesEncoded;

    const result: number[] = candidates.map((_, i) => {
      return visitedCategories.reduce((sum, category) => {
        return sum + dataframe[category][i] * visited[category];
      }, 0);
    });

    let ranked: [number, number][] = candidates.map((place, i) => [place.idPlace, result[i]]);
    ranked.sort(customSort);

    return ranked;
  }

  recommend(visited: RecommendPlace[], candidates: RecommendPlace[]) {
    const visitedRanking = this.rankVisited(visited);
    const candidatesRanked = this.rankCandidates(candidates, visitedRanking);
    return candidatesRanked;
  }
}