Un système de recommandation de filtrage collaboratif en Java

1. Introduction

Dans ce didacticiel, nous apprendrons tout sur l’algorithme Slope One en Java.

Nous montrerons également l’exemple d’implémentation du problème du filtrage collaboratif (CF) - une technique d’apprentissage automatique utilisée par les systèmes de recommandation .

Cela peut être utilisé, par exemple, pour prédire les intérêts des utilisateurs pour des éléments spécifiques.

2. Filtrage collaboratif

L’algorithme Slope One est un système de filtrage collaboratif basé sur les éléments.

Cela signifie qu’il est complètement basé sur le classement des éléments utilisateur. Lorsque nous calculons la similarité entre les objets, nous ne connaissons que l’historique des classements, pas le contenu lui-même. Cette similarité est ensuite utilisée pour prédire les classements d’utilisateurs potentiels pour les paires utilisateur-élément non présentes dans l’ensemble de données.

Le image ci-dessous montre le processus complet d’obtention et de calcul de la note pour l’utilisateur spécifique:

Au début, les utilisateurs évaluent différents éléments du système. Ensuite, l’algorithme calcule les similitudes. Après cela, le système établit des prédictions pour les évaluations d’élément utilisateur, que l’utilisateur n’a pas encore notées.

Pour plus de détails sur le filtrage collaboratif, on peut se référer à https://en.wikipedia.org/wiki/Filter Collaboratif pour l’article Wikipedia].

3. L’algorithme Slope One

Slope One a été désigné comme la forme la plus simple de filtrage collaboratif basé sur des éléments, non trivial, basé sur les notations. Il prend en compte les informations de tous les utilisateurs qui ont évalué le même élément et des autres éléments évalués par le même utilisateur pour calculer la matrice de similarité.

Dans notre exemple simple, nous allons prédire le classement des utilisateurs sur les éléments du magasin.

Commençons par un modèle Java simple pour notre problème et notre domaine.

3.1. Java Model

Dans notre modèle, nous avons deux objets principaux: les objets et les utilisateurs. La classe Item contient le nom de l’élément:

private String itemName;

D’autre part, la classe User contient le nom d’utilisateur:

private String username;

Enfin, nous avons une classe InputData qui sera utilisée pour initialiser les données. Supposons que nous créons cinq produits différents dans le magasin:

List<Item> items = Arrays.asList(
  new Item("Candy"),
  new Item("Drink"),
  new Item("Soda"),
  new Item("Popcorn"),
  new Item("Snacks")
);

De plus, nous allons créer trois utilisateurs qui ont évalué de manière aléatoire certaines des valeurs mentionnées ci-dessus en utilisant l’échelle allant de 0,0 à 1,0, où 0 signifie aucun intérêt, 0,5 d’une manière ou d’une autre et 0 totalement intéressé. À la suite de l’initialisation des données, nous obtiendrons un Map avec les données de classement des éléments de l’utilisateur:

Map<User, HashMap<Item, Double>> data;

3.2. Matrices Différences et Fréquences

Sur la base des données disponibles, nous allons calculer les relations entre les éléments, ainsi que le nombre d’occurrences d’éléments. Pour chaque utilisateur, nous vérifions son classement des éléments:

for (HashMap<Item, Double> user : data.values()) {
    for (Entry<Item, Double> e : user.entrySet()) {
       //...
    }
}

À l’étape suivante, nous vérifions si l’élément existe dans nos matrices. S’il s’agit d’une première occurrence, nous créons la nouvelle entrée dans les cartes:

if (!diff.containsKey(e.getKey())) {
    diff.put(e.getKey(), new HashMap<Item, Double>());
    freq.put(e.getKey(), new HashMap<Item, Integer>());
}

La première matrice est utilisée pour calculer les différences entre les évaluations des utilisateurs. Ses valeurs peuvent être positives ou négatives (car la différence entre les évaluations peut être négative) et sont stockées sous la forme Double . D’autre part, les fréquences sont stockées sous forme de valeurs Integer .

Dans l’étape suivante, nous allons comparer les évaluations de tous les éléments:

for (Entry<Item, Double> e2 : user.entrySet()) {
    int oldCount = 0;
    if (freq.get(e.getKey()).containsKey(e2.getKey())){
        oldCount = freq.get(e.getKey()).get(e2.getKey()).intValue();
    }

    double oldDiff = 0.0;
    if (diff.get(e.getKey()).containsKey(e2.getKey())){
        oldDiff = diff.get(e.getKey()).get(e2.getKey()).doubleValue();
    }

    double observedDiff = e.getValue() - e2.getValue();
    freq.get(e.getKey()).put(e2.getKey(), oldCount + 1);
    diff.get(e.getKey()).put(e2.getKey(), oldDiff + observedDiff);
}

Si quelqu’un a déjà évalué l’élément, nous augmentons le nombre de fréquences de un. De plus, nous vérifions la différence moyenne entre les évaluations de l’élément et calculons le nouveau observedDiff .

  • Veuillez noter que nous avons mis la somme de oldDiff et observedDiff comme nouvelle valeur d’un élément. **

Enfin, nous calculons les scores de similarité à l’intérieur des matrices:

for (Item j : diff.keySet()) {
    for (Item i : diff.get(j).keySet()) {
        double oldValue = diff.get(j).get(i).doubleValue();
        int count = freq.get(j).get(i).intValue();
        diff.get(j).put(i, oldValue/count);
    }
}

La logique principale consiste à diviser la différence d’évaluation d’élément calculée par le nombre de ses occurrences. Après cette étape, nous pouvons imprimer notre matrice des différences finales.

3.3. Pédictions

En tant que partie principale du Slope One, nous allons prédire toutes les notations manquantes sur la base des données existantes. Pour ce faire, nous devons comparer les notations d’élément utilisateur avec la matrice de différences calculée à l’étape précédente:

for (Entry<User, HashMap<Item, Double>> e : data.entrySet()) {
    for (Item j : e.getValue().keySet()) {
        for (Item k : diff.keySet()) {
            double predictedValue =
              diff.get(k).get(j).doubleValue() + e.getValue().get(j).doubleValue();
            double finalValue = predictedValue **  freq.get(k).get(j).intValue();
            uPred.put(k, uPred.get(k) + finalValue);
            uFreq.put(k, uFreq.get(k) + freq.get(k).get(j).intValue());
        }
    }
   //...
}

Après cela, nous devons préparer les prédictions «propres» en utilisant le code ci-dessous:

HashMap<Item, Double> clean = new HashMap<Item, Double>();
for (Item j : uPred.keySet()) {
    if (uFreq.get(j) > 0) {
        clean.put(j, uPred.get(j).doubleValue()/uFreq.get(j).intValue());
    }
}
for (Item j : InputData.items) {
    if (e.getValue().containsKey(j)) {
        clean.put(j, e.getValue().get(j));
    } else {
        clean.put(j, -1.0);
    }
}

L’astuce à considérer avec un jeu de données plus volumineux consiste à utiliser uniquement les entrées d’élément ayant une valeur de fréquence élevée (par exemple> 1). Veuillez noter que si la prédiction n’est pas possible, sa valeur sera égale à -1.

  • Enfin, note très importante. Si notre algorithme fonctionnait correctement, nous devrions recevoir les prédictions pour les éléments que l’utilisateur n’a pas notés, mais également les évaluations répétées des éléments qu’il a cotés ** . Ces évaluations répétées ne devraient pas changer, sinon cela signifie qu’il ya un bogue dans l’implémentation de votre algorithme.

3.4. Conseils

Il y a peu de facteurs majeurs qui affectent l’algorithme Slope One. Voici quelques conseils pour augmenter la précision et le temps de traitement:

  • Pensez à obtenir les classements d’utilisateurs du côté de la base de données pour les grandes données.

ensembles ** fixer le délai pour la récupération des notes, selon l’intérêt des personnes

changer au fil du temps - cela réduira également le temps requis pour traiter des données d’entrée ** diviser des ensembles de données volumineux en ensembles plus petits - vous n’avez pas besoin de calculer

prévisions pour tous les utilisateurs chaque jour; vous pouvez vérifier si l’utilisateur a interagi avec l’élément prévu, puis l’ajouter/le supprimer de la file d’attente de traitement pour le jour suivant

4. Conclusion

Dans ce tutoriel, nous avons pu découvrir l’algorithme Slope One.

De plus, nous avons introduit le problème du filtrage collaboratif pour les systèmes de recommandation d’articles.

La mise en œuvre complète de ce didacticiel est disponible à l’adresse https://github.com/eugenp/tutorials/tree/master/algorithms-miscellaneous-2 du projet GitHub].