J'ai un dataframe avec différentes personnes. Chaque ligne contient des attributs qui caractérisent la personne individuelle. Fondamentalement, j'ai besoin de quelque chose comme un filtre ou un algorithme de correspondance qui pondère des attributs spécifiques. Le dataframe ressemble à ceci:
sex food age kitchen 0 m 0 young 0 1 f 0 young 1 2 m 1 young 2 3 f 3 old 0 4 m 4 young 1 5 f 3 young 2
Le dataframe df
ressemble à ceci:
df= pd.DataFrame({ 'sex' : [m,f,m,f,m,f], 'food' : [0,0,1,3,4,3], 'age': [young, young, young, old, young, young] 'kitchen': [0,1,2,0,1,2], })
Je recherche un algorithme qui regroupe toutes les personnes du dataframe par paires. Mon plan est de trouver des paires de deux personnes en fonction des attributs suivants:
Une personne doit avoir une cuisine (cuisine = 1)
Il est important qu'au moins une personne dispose d'une cuisine.
cuisine = 0 -> personne n'a pas de cuisine
cuisine = 1 -> personne a une cuisine
cuisine = 2 -> personne a une cuisine mais seulement en cas d'urgence (quand il n'y a pas d'autre option)
Mêmes préférences alimentaires
food = 0 -> mangeur de viande
food = 1 -> n'a pas d'importance
nourriture = 2 -> vegan
nourriture = 3 -> végétarienne
Un mangeur de viande (nourriture = 0) peut être jumelé avec une personne qui ne se soucie pas des préférences alimentaires (nourriture = 1) mais ne peut pas être jumelé avec un végétalien ou végétarien. Un végétalien (nourriture = 2) correspond le mieux à un végétarien (nourriture = 3) et, si nécessaire, peut aller avec de la nourriture = 1. Et ainsi de suite ...
Âge similaire
Il y a neuf groupes d'âge: 10-18 ans; 18-22; 22-26; 26 à 29, 29 à 34; 34-40; 40-45; 45-55 et 55-75. Les personnes du même groupe d'âge correspondent parfaitement. Les jeunes groupes d'âge avec les groupes plus âgés ne correspondent pas très bien. Des groupes d'âge similaires correspondent un peu mieux. Il n'y a pas de condition clairement définie. La signification de «vieux» et «jeune» est relative.
Le sexe n'a pas d'importance. Il existe de nombreuses combinaisons de paires possibles. Étant donné que ma base de données réelle est très longue (3000 lignes), je dois trouver une solution automatisée. Une solution qui me donne les meilleures paires dans un dataframe ou un dictionnaire ou autre chose.
Je ne sais vraiment pas comment aborder ce problème. Je cherchais des problèmes similaires sur Stack Overflow, mais je n'ai rien trouvé de convenable. C'était surtout trop théorique. De plus, je n'ai rien trouvé qui correspond vraiment à mon problème.
Ma sortie attendue ici serait, par exemple, un dictionnaire (je ne sais pas comment) ou un dataframe qui est trié de manière à ce que toutes les deux lignes puissent être vu comme une paire.
Contexte: Le but est de faire des paires pour des activités de temps libre. Par conséquent, je pense que les personnes appartenant à des groupes d'âge identiques ou similaires partagent le même intérêt, c'est pourquoi je veux tenir compte de ce fait dans mon code.
3 Réponses :
Cela me semble être un problème très intéressant. Il existe plusieurs façons de résoudre ce problème. Je vous en indiquerai une, mais je vous relierai à une autre solution qui, selon moi, est en quelque sorte liée.
Une approche possible peut être de créer une colonne supplémentaire dans votre cadre de données, y compris un "code" qui fait référence aux attributs donnés. Par exemple:
import re haskitchen = r'(\S\S1) hasnokitchen = r'(\S\S0) df_dict = df.to_dict match_kitchen = re.findall(haskitchen, df_dict) match_nokitchen = re.dinfall(hasnokitchen, df_dict) kitchendict["Has kitchen"] = [match_kitchen] kitchendict["Has no kitchen"] = [match_notkitchen]
Ceci " code 'est composé de courts métrages de vos attributs. Puisque le sexe n'a pas d'importance, le premier signe dans le code représente la «nourriture», le deuxième pour «l'âge» et le troisième pour la «cuisine».
4y1 = food 4, age young, kitchen 1.
Sur la base de ces codes, vous pouvez créer un modèle. Je vous recommande de travailler avec Expressions régulières pour cela. Vous pouvez ensuite écrire quelque chose comme ceci:
sex food age kitchen code 0 m 0 young 0 0y0 1 f 0 young 1 0y1 2 m 1 young 2 1y2 3 f 3 old 0 3o0 4 m 4 young 1 4y1 5 f 3 young 2 3y2
Sur cette base, vous pouvez boucler sur les entrées et les assembler comme vous le souhaitez. Il y a peut-être une solution beaucoup plus simple et je n'ai pas vérifié le code, mais cela m'est venu à l'esprit. Une chose est sûre: Utilisez des expressions régulières pour la correspondance.
Eh bien, testons la cuisine.
people = 0 x = 0 for I in(kitchen): x = x + 1 for A in (food): if (I != 0): x = x + 1 print("Kitchen Found) else: print("No kitchen") for J in(food): if(i == J): print("food match found") elif(A == 0): if(J == 1): print("food match found for person" + x) elif(A == 2 or A == 3): if(J == 2 or J == 3 or J == 1): print("food match found for person" + x)
Bon maintenant que nous avons trouvé une cuisine chez les gens qui ont une maison de cuisine, trouvons les gens sans cuisine quelqu'un avec une nourriture similaire préférences. Créons une variable qui nous indique combien de personnes ont une cuisine (x). Faisons également la variable person pour compter les personnes.
for I in(kitchen): if (I != 0): print("Kitchen Found) else: print("No kitchen")
Je travaille actuellement sur la partie âge en ajustant quelque chose
J'ai fait un ajout en mettant 'nom'
comme clé pour identifier la personne.
L'approche est que j'ai noté les valeurs qui sont ensuite utilisé pour filtrer les paires finales selon les conditions données.
Pour les scores de cuisine, nous avons utilisé:
Nous vérifions que si [score cuisine de l'enregistrement 1] + [score de la cuisine de l'enregistrement 2] est supérieur que zéro . Comme les cas suivants seront là:
Pour les notes alimentaires, nous avons utilisé:
Nous vérifions si * [score alimentaire de l'enregistrement 1] * [score alimentaire de l'enregistrement 2] * est supérieur ou égal fort > à Zéro . Comme les cas suivants seront là:
Pour la notation des groupes d'âge, nous avons attribué certaines valeurs aux groupes comme suit:
Pour calculer le score d'âge, la formule suivante a été utilisée:
age_score = round ((1 - (abs (Age Group Value Person 1 - Age Group Value of Person 2) / 10)), 2)
Dans la formule ci-dessus, nous calculons a été fait comme suit:
Les cas seront comme:
round (1 - (abs (2 - 2) / 10), 2) = 1.0
round (1 - (abs (8 - 8) / 10), 2) = 1.0
round (1 - (abs (2-8) / 10), 2) = 0.4
round (1 - (abs (1 - 9) / 10), 2) = 0.2
Pour calculer le score final, nous avons utilisé:
Score final = score alimentaire + score cuisine + score âge
Ensuite, nous avons trié les données sur le score final pour obtenir les meilleures paires.
0 1 2 48 sabastein smith 4.0 10 mary allen 3.5 51 sabastein katie 3.4 102 smith jim 3.4 54 sabastein jim 3.4 99 smith katie 3.4 61 anna katie 3.3 45 sabastein anna 3.1 58 anna smith 3.1 14 mary rose 3.0 12 mary mimi 3.0 84 allen cinthy 3.0 98 smith mimi 2.9 105 waterman katie 2.9 11 mary jolly 2.9 50 sabastein mimi 2.9 40 emily katie 2.9 52 sabastein john 2.9 100 smith john 2.9 90 rock smith 2.8 47 sabastein rock 2.8 0 jacob mary 2.8 17 mary paul 2.8 13 mary john 2.8 119 katie jim 2.8 116 mimi paul 2.8 111 mimi john 2.8 103 smith paul 2.7 85 allen paul 2.7 120 katie paul 2.7 .. ... ... ...
name sex food age kitchen k_scr f_scr a_scr 0 jacob m 0 10-18 0 0.0 -1 1 1 mary f 0 22-26 1 1.0 -1 3 2 rick m 1 29-34 2 0.5 0 5 3 emily f 3 40-45 0 0.0 1 7 4 sabastein m 2 18-22 1 1.0 1 2 5 anna f 3 34-40 2 0.5 1 6 6 christina f 1 55-75 2 0.5 0 9 7 allen m 0 45-55 1 1.0 -1 8 8 jolly f 0 26-29 0 0.0 -1 4 9 rock m 3 26-29 0 0.0 1 4 10 smith m 3 18-22 1 1.0 1 2 11 waterman m 2 55-75 0 0.0 1 9 12 mimi f 1 22-26 1 1.0 0 3 13 katie f 2 45-55 1 1.0 1 8 14 john m 1 10-18 1 1.0 0 1 15 rose f 0 22-26 0 0.0 -1 3 16 leonardo m 1 40-45 2 0.5 0 7 17 cinthy f 0 45-55 0 0.0 -1 8 18 jim m 3 10-18 2 0.5 1 1 19 paul m 1 29-34 1 1.0 0 5
import pandas as pd import numpy as np # Creating the DataFrame, here I have added the attribute 'name' for identifying the record. df = pd.DataFrame({ 'name' : ['jacob', 'mary', 'rick', 'emily', 'sabastein', 'anna', 'christina', 'allen', 'jolly', 'rock', 'smith', 'waterman', 'mimi', 'katie', 'john', 'rose', 'leonardo', 'cinthy', 'jim', 'paul'], 'sex' : ['m', 'f', 'm', 'f', 'm', 'f', 'f', 'm', 'f', 'm', 'm', 'm', 'f', 'f', 'm', 'f', 'm', 'f', 'm', 'm'], 'food' : [0, 0, 1, 3, 2, 3, 1, 0, 0, 3, 3, 2, 1, 2, 1, 0, 1, 0, 3, 1], 'age' : ['10-18', '22-26', '29-34', '40-45', '18-22', '34-40', '55-75', '45-55', '26-29', '26-29', '18-22', '55-75', '22-26', '45-55', '10-18', '22-26', '40-45', '45-55', '10-18', '29-34'], 'kitchen' : [0, 1, 2, 0, 1, 2, 2, 1, 0, 0, 1, 0, 1, 1, 1, 0, 2, 0, 2, 1], }) # Adding a normalized field 'k_scr' for kitchen df['k_scr'] = np.where((df['kitchen'] == 2), 0.5, df['kitchen']) # Adding a normalized field 'f_scr' for food df['f_scr'] = np.where((df['food'] == 1), 0, df['food']) df['f_scr'] = np.where((df['food'] == 0), -1, df['f_scr']) df['f_scr'] = np.where((df['food'] == 2), 1, df['f_scr']) df['f_scr'] = np.where((df['food'] == 3), 1, df['f_scr']) # Adding a normalized field 'a_scr' for age df['a_scr'] = np.where((df['age'] == '10-18'), 1, df['age']) df['a_scr'] = np.where((df['age'] == '18-22'), 2, df['a_scr']) df['a_scr'] = np.where((df['age'] == '22-26'), 3, df['a_scr']) df['a_scr'] = np.where((df['age'] == '26-29'), 4, df['a_scr']) df['a_scr'] = np.where((df['age'] == '29-34'), 5, df['a_scr']) df['a_scr'] = np.where((df['age'] == '34-40'), 6, df['a_scr']) df['a_scr'] = np.where((df['age'] == '40-45'), 7, df['a_scr']) df['a_scr'] = np.where((df['age'] == '45-55'), 8, df['a_scr']) df['a_scr'] = np.where((df['age'] == '55-75'), 9, df['a_scr']) # Printing DataFrame after adding normalized score values print(df) commonarr = [] # Empty array for our output dfarr = np.array(df) # Converting DataFrame to Numpy Array for i in range(len(dfarr) - 1): # Iterating the Array row for j in range(i + 1, len(dfarr)): # Iterating the Array row + 1 # Check for Food Condition to include relevant records if dfarr[i][6] * dfarr[j][6] >= 0: # Check for Kitchen Condition to include relevant records if dfarr[i][5] + dfarr[j][5] > 0: row = [] # Appending the names row.append(dfarr[i][0]) row.append(dfarr[j][0]) # Appending the final score row.append((dfarr[i][6] * dfarr[j][6]) + (dfarr[i][5] + dfarr[j][5]) + (round((1 - (abs(dfarr[i][7] - dfarr[j][7]) / 10)), 2))) # Appending the row to the Final Array commonarr.append(row) # Converting Array to DataFrame ndf = pd.DataFrame(commonarr) # Sorting the DataFrame on Final Score ndf = ndf.sort_values(by=[2], ascending=False) print(ndf)
Cette solution a une portée supplémentaire d'optimisation.
Merci beaucoup pour cette excellente approche de mon problème et désolé pour ma réponse tardive. J'ai une autre question que j'aimerais que vous posiez: 1) Disons que j'ai plusieurs groupes d'âge. Dans mon cas, j'ai 9 groupes d'âge. Je suppose que je dois changer l'équation. Cependant, je ne sais pas quel score je dois attribuer à chaque tranche d'âge. Peut-être pouvez-vous m'aider ici!
@PParker Merci pour la réponse. Veuillez accepter comme bonne réponse si cela a fonctionné pour vous. Pour plusieurs groupes d'âge, j'ai besoin de connaître la relation entre ces neuf groupes d'âge et leurs priorités de correspondance pour définir l'équation. Je vais essayer.
Merci de votre aide! J'ai neuf groupes d'âge: 10-18 ans; 18-22; 22-26; 26 à 29, 29 à 34; 34-40; 40-45; 45-55 et 55-75. Les personnes du même groupe d'âge correspondent parfaitement. Les jeunes groupes d'âge avec les groupes plus âgés ne correspondent pas très bien. Des groupes d'âge similaires correspondent un peu mieux. Il n'y a pas de condition clairement définie. La signification de «vieux» et «jeune» est relative. Contexte: Le but est de former des paires pour des activités de temps libre. Par conséquent, je pense que les personnes appartenant à des groupes d'âge identiques ou similaires partagent le même intérêt, c'est pourquoi je veux tenir compte de ce fait dans mon code.
Je vais essayer si nous pouvons utiliser une sorte de score de distance entre les groupes. Plus le groupe est éloigné, moins le score est élevé. Mais il faut voir qu'en même temps, cela ne devrait pas faire de biais de score global ou remplacer l'effet d'autres propriétés. Laissez-moi penser à une solution.
@PParker J'ai mis à jour la question avec les informations supplémentaires que vous avez fournies sur les groupes d'âge et mis à jour la réponse et son explication également. Maintenant, le programme considère la distance entre les deux groupes d'âge des personnes et les note ensuite sur la base de leur distance. J'espère que cela t'aides.
@ AnidhyaBhatnagar Merci beaucoup pour cette solution extraordinaire. Cela fonctionne très bien. Merci également pour vos explications détaillées. Permettez-moi de vous poser quelques questions plus générales: 1.) Est-il correct de dire que (selon les personnes) tout le monde n'a pas de partenaire? 2.) En fonction du score, comment choisiriez-vous le partenaire réel? Je suis confus, car par exemple sabastein a le score le plus élevé avec smith (4,0) mais smith a le score le plus élevé avec jim (3,4). Peut-être existe-t-il un moyen explicite de sélectionner les paires dans la trame de données finale?
@PParker 1.) Oui, il est correct de dire que selon les personnes et leurs caractéristiques, tout le monde n'aura pas de partenaire. 2.) Ne vous méprenez pas, Sabastein a le score le plus élevé avec Smith et le Smith a le score le plus élevé avec Sabastein. Parce que si vous correspondez à Sabastein -> Smith ou Smith -> Sabastein, le score sera le même 4.0. Ainsi, lorsque vous choisissez une paire, dites (Sabastein & Smith), ignorez toutes les autres paires qui ont Sabastein ou Smith. Ainsi, vous en tirerez des paires uniques.
Merci beaucoup pour votre réponse. Je viens de réaliser qc. nouveau: nous avons maintenant cette trame de données très longue avec différentes combinaisons de paires et scores. Il s'avère qu'une personne peut être mieux jumelée à plusieurs personnes. Par exemple, Anna travaille mieux avec Katie (3,3), mais Christina travaille également mieux avec Katie (2,4). Il existe de nombreux exemples comme celui-ci. Je suppose donc que la meilleure approche est de créer une fonction qui sélectionne les meilleures paires de la trame de données. Le but est de trouver autant de bonnes paires que possible. Vous pouvez peut-être commenter cela. Comment aborderiez-vous cela en général?
@PParker Oui! le but ultime est de faire correspondre et de créer les meilleures paires. Eh bien, c'est une question délicate. Penser à cela nécessite un certain temps et travailler avec un échantillon pour arriver à la meilleure solution. (comme supposons que A et B correspondent le mieux, mais A et C, B et D ont une certaine correspondance, mais C et D ne correspondent certainement pas, ici, il serait préférable que A et C correspondent B et D correspondent.) I Je vais un peu occupé maintenant quelques jours - je le regarderai le week-end prochain. Jusque-là, vous pouvez essayer de retirer une paire, puis de supprimer tous les enregistrements suivants avec l'un ou l'autre de n'importe quel côté, puis d'en choisir un unique et de le défausser, etc.
@PParker En référence à votre déclaration "Si possible, les paires sont dans le même groupe d'âge. Si ce n'est pas possible, alors peut-être dans un groupe d'âge similaire." Avez-vous un âge numérique dans la colonne d'âge ou seulement deux valeurs de chaîne: «Jeune» et «Vieux»?
@PParker Vous pouvez consulter les ressources suivantes: Maximiser les appariements sous réserve de contrainte de distance , Algorithme Blossom , Correspondance avec les contraintes , Problème d'attribution , algorithme hongrois .
@AnidhyaBhatnagar Dans mon exemple simplifié, je n'ai que deux groupes d'âge (jeunes et vieux). Cependant, dans la base de données réelle, j'ai un âge numérique. Mon projet est de créer plusieurs tranches d'âge (par exemple "très jeune", "jeune", "vieux", "très vieux", ...).