2 votes

Comment puis-je exécuter l'analyse regroupée par la valeur de la colonne, au lieu d'utiliser l'ensemble des données

Je travaille sur un système de recommandation de produits en Python (voir réponse de Mohsin Hasan).

Le script prend simplement deux variables (UserId, ItemId) en entrée, et donne en sortie le score d'affinité entre deux produits.

Cependant, j'ai ajouté une troisième colonne (pays). Je veux faire l'analyse séparément, par pays (pas l'ensemble du jeu de données).

À l'origine, j'utilisais R, où la fonction 'group_by' de dplyr devrait aider. Mais actuellement, je suis bloqué (voir mes tentatives ci-dessous). Avez-vous une idée de comment je pourrais réaliser cette analyse par pays? (J'ai l'impression que 'pandas.DataFrame.groupby' pourrait résoudre cela, au lieu de ma tentative d'utiliser une boucle for).

Données d'exemple (veuillez noter : la seule différence est que j'ai ajouté la colonne pays) :

UserId      ItemId          Pays

1           Babyphone       Pays-Bas
1           Babyphone       Pays-Bas
1           Machine à café   Pays-Bas
2           Machine à café   Pays-Bas
2           Rasoir          Pays-Bas
3           Rasoir          Pays-Bas
3           Machine à café   Pays-Bas
4           Machine à café   Pays-Bas
4           Rasoir          Pays-Bas
4           Blender         Pays-Bas
5           Blender         Pays-Bas
5           Babyphone       Pays-Bas
5           Rasoir          Pays-Bas
6           Rasoir          Pays-Bas
7           Machine à café   Pays-Bas
7           Machine à café   Pays-Bas
8           Babyphone       Pays-Bas
9           Blender         Pays-Bas
9           Blender         Pays-Bas   
1           Babyphone       Allemagne
1           Babyphone       Allemagne
1           Machine à café   Allemagne
2           Machine à café   Allemagne
2           Rasoir          Allemagne
3           Rasoir          Allemagne
3           Machine à café   Allemagne
4           Machine à café   Allemagne
4           Rasoir          Allemagne
4           Blender         Allemagne
5           Blender         Allemagne
5           Babyphone       Allemagne
5           Rasoir          Allemagne
6           Rasoir          Allemagne
7           Machine à café   Allemagne
7           Machine à café   Allemagne
8           Babyphone       Allemagne
9           Blender         Allemagne
9           Blender         Allemagne

Code fonctionnant -original- (fonctionnant avec UserId et ItemId, sans Pays)

# main est notre jeu de données.

# obtenir les articles uniques
articles = set(main.productId)

n_users = len(set(main.userId))

# créer un dictionnaire des articles et des utilisateurs ayant acheté cet article
utilisateurs_article = main.groupby('productId')['userId'].apply(set).to_dict()

# itérer sur les combinaisons d'article1 et d'article2 et stocker les scores
resultat = []
for article1, article2 in itertools.combinations(articles, 2):

  score = len(utilisateurs_article[article1] & utilisateurs_article[article2]) / n_users
  tuples_article = [(article1, article2), (article2, article1)]
  resultat.append((article1, article2, score))
  resultat.append((article2, article1, score)) # stocker également le score pour l'ordre inverse

# convertir les résultats en un dataframe
resultat = pd.DataFrame(resultat, columns=["item1", "item2", "score"])

Ma tentative (avec le pays, mais cela ne fonctionne pas). Qu'ai-je essayé ?

  1. Filtrer le jeu de données par pays (oui, c'est nul car ce n'est pas dynamique)
  2. Boucler sur les dataframes (chaque pays a un dataframe)
  3. Essayer d'insérer la solution (voir ci-dessus), et l'appliquer aux dataframes séparément.
  4. Comme vous pouvez le voir, malheureusement ça ne fonctionne pas...

       Pays-Bas = df.loc[df['Country'] == 'Pays-Bas']
       Allemagne     = df.loc[df['Country'] == 'Allemagne']
       resultats = []
       for jeu_de_donnees in (Pays-Bas, Allemagne):
           for index, ligne in jeu_de_donnees.iterrows():
           Pays = ligne['Country'] # Besoin de lier le nom du dataframe aux résultats
    
           articles = set(jeu_de_donnees.ItemId) # Obtenir les articles uniques par pays
           n_users = len(set(jeu_de_donnees.UserId) # Obtenir le nombre d'utilisateurs uniques par pays
           utilisateurs_article = jeu_de_donnees.groupby('ItemId'['UserId'].apply(set).to_dict() # J'ai essayé d'ajouter le pays ici, mais sans résultats
    
           for article1, article2 in itertools.combinations(articles, 2):
                print("article1", article1)
                print("article2", article2)
                score = len(utilisateurs_article[article1] & utilisateurs_article[article2]) / n_users
                tuples_article = [(article1, article2), (article2, article1)]
                resultats.append((article1, article2, score))
                resultats.append((article2, article1, score)) # stocker également le score pour l'ordre inverse
                resultats = pd.DataFrame(resultats, columns=["item1", "item2", "score"])

Édition 1 : Sortie attendue

description de l'image

Édition 2 Comment le score est-il calculé ? Le score représente : Combien de clients achètent une combinaison de produits ensemble.

Par exemple, dans les données, vous voyez que Rasoir & Machine à café = 0,333 (car 3 personnes, sur les 9 personnes, ont acheté cette combinaison PAR PAYS). Dans le premier code, le score fonctionne parfaitement. Mais je ne parviens pas à le faire fonctionner par pays (c'est là que réside le problème clé).

Merci d'avance !

1voto

Zaraki Kenpachi Points 4644

Voici

\=^..^=

Comme vous l'avez mentionné, group by sera utilisé. Déplacez d'abord votre boucle score dans une fonction avec un champ supplémentaire 'pays' et utilisez-la sur les cadres de données groupés, comme ceci :

import pandas as pd
import itertools

Déplacez le score dans une fonction :

def get_score(item):
    country = item[0]
    df = item[1]

    # obtenir des éléments uniques
    items = set(df.ItemId)
    n_users = len(set(df.UserId))

    # créer un dictionnaire de l'élément et des utilisateurs ayant acheté cet élément
    item_users = df.groupby('ItemId')['UserId'].apply(set).to_dict()

    # itérer sur les combinaisons d'élément1 et d'élément2 et stocker les scores
    result = []
    for item1, item2 in itertools.combinations(items, 2):

      score = len(item_users[item1] & item_users[item2]) / n_users
      item_tuples = [(item1, item2), (item2, item1)]
      result.append((item1, item2, score, country))
      result.append((item2, item1, score, country)) # stocker le score pour l'ordre inverse également

    # convertir les résultats en un cadre de données
    result = pd.DataFrame(result, columns=["item1", "item2", "score", 'country'])
    return result

Regroupez les données par pays et bouclez ensuite sur chaque groupe pour obtenir le score :

grouped_data = df.groupby(['Country'])

df_list = []
for item in list(grouped_data):
    df_list.append(get_score(item))

# concaténer les cadres
df = pd.concat(df_list)
# supprimer les lignes avec un score de 0
df = df[df['score'] > 0]

Sortie :

            item1          item2     score      country
0       BabyPhone        Blender  0.111111      Allemagne
1         Blender      BabyPhone  0.111111      Allemagne
4       BabyPhone         Shaver  0.111111      Allemagne
5          Shaver      BabyPhone  0.111111      Allemagne
8         Blender  CoffeeMachine  0.111111      Allemagne
9   CoffeeMachine        Blender  0.111111      Allemagne
10        Blender         Shaver  0.222222      Allemagne
11         Shaver        Blender  0.222222      Allemagne
14  CoffeeMachine         Shaver  0.333333      Allemagne
15         Shaver  CoffeeMachine  0.333333      Allemagne
16  CoffeeMachine      Babyphone  0.111111      Allemagne
17      Babyphone  CoffeeMachine  0.111111      Allemagne
0       BabyPhone        Blender  0.111111      Pays-Bas
1         Blender      BabyPhone  0.111111      Pays-Bas
4       BabyPhone         Shaver  0.111111      Pays-Bas
5          Shaver      BabyPhone  0.111111      Pays-Bas
8         Blender  CoffeeMachine  0.111111      Pays-Bas
9   CoffeeMachine        Blender  0.111111      Pays-Bas
10        Blender         Shaver  0.222222      Pays-Bas
11         Shaver        Blender  0.222222      Pays-Bas
14  CoffeeMachine         Shaver  0.333333      Pays-Bas
15         Shaver  CoffeeMachine  0.333333      Pays-Bas
16  CoffeeMachine      Babyphone  0.111111      Pays-Bas
17      Babyphone  CoffeeMachine  0.111111      Pays-Bas

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X